home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1995 May / cd Ware (Juegos) Epimundo.iso / DOS / UT_SYSTM / VOL13N20.ZIP / PCMKEY.ZIP / PCMKEY.ASM next >
Encoding:
Assembly Source File  |  1994-10-25  |  110.2 KB  |  3,785 lines

  1.      page    66,132
  2. ;============================================================================
  3. ; PCMKEY adds a command line stack, a command line editor, and
  4. ; an alias function to COMMAND.COM.  
  5. ;
  6. ; PCMKEY.ASM  Copyright 1990 Doug Boling and Jeff Prosise
  7. ;             Copyright 1994 Douglas Boling
  8. ;
  9. ;============================================================================
  10. MAXKEYS        equ    64
  11. STACKSIZE    equ    256
  12. RES_STACK       equ     offset end_of_resident + STACKSIZE
  13. INSTDATASIZE    equ    offset DataBlockEnd - offset DataBlock
  14.  
  15.         code    segment
  16.         assume    cs:code
  17.  
  18.         org    2ch
  19. env_segment    dw    ?            ;Word containing the segment
  20.                         ;  of the program's env. block.
  21.         org    80h
  22. command_tail    db    ?            ;Offset of the command tail.
  23.  
  24.         org    100h
  25.  
  26. main:        jmp    initialize
  27. program        db    13,10,"PCMKEY 1.0 "
  28. copyright    db    "Copyright 1990 Doug Boling and Jeff Prosise",10,13
  29.                   db    "Copyright 1994 Douglas Boling",10,13
  30.             db      "Published in PC Magazine, November 22, 1994"
  31. endmsg            db      13,10,0,1Ah
  32.  
  33. pick_prompt    db    11,"Cmd number:"
  34. pick_prompt_end    =    $
  35.  
  36. dos_version    dw    0            ;DOS Version number
  37. win_enhanced    db    0
  38. temp_buff    dd    ?            ;Addr of temp buffer
  39. work_buff_ptr    dw    ?            ;Pointer to alias working buff
  40. ;
  41. ;Switcher global data structures
  42. ;
  43. StartupInfo     =       $
  44.  sisVersion     dw      3                       ;Switcher structure ID
  45.  sisNextDev     dd      0                       ;Ptr to prev startup structure
  46.  sisVirtDevFile dd      0                       ;Ptr to name of opt dev drvr
  47.  sisReferenceData dd    0                       ;Data for Win dev drivr
  48.  sisInstData    dd      0                       ;Ptr to instance mem list
  49.  
  50. DataBlockPtr    dd      0                       ;Ptr to instance data
  51. DataBlockSize   dw      0                       ;Size of instance data
  52. StackBlockPtr   dd      0                       ;Ptr to instance stack
  53. StackBlockSize  dw      0                       ;Size of instance stack
  54. TempBlockPtr    dd      0                       ;Ptr to temp buffer
  55. TempBlockSize   dw      128                     ;Size of temp buffer
  56.             dd      0                       ;Ptr to next block = 0 to
  57.             dw      0                       ;  terminate list
  58. ;
  59. ; Instance data
  60. ;
  61. DataBlock    =    $
  62. aliaslist_ptr    dd    ?                     ;Pointer to alias list.
  63. aliaslist_size    dw    ?             ;Pointer to end of list seg
  64.  
  65. chk_alias    db    1            ;Alias enable flag.
  66. minlength    db    1            ;Minimum len of cmd to stack
  67. cmdcom_env    dw    0            ;Segment of master environment
  68.  
  69. saved_ss    dw    ?
  70. saved_sp    dw    ?
  71. int21h        dd    -1            ;Int 21 vector (DOS)
  72. int2fh        dd    -1            ;Int 2f vector (DOS MULTIPLEX)
  73.  
  74. multiplex_id    db    0dbh            ;Program ID for multiplex int
  75. last_click    db    0            ;Used by GetKey routine
  76. ;
  77. ; Cmd line code vars
  78. ;
  79. bufferptr    db    ?            ;Input buffer pointer
  80. columns        db    ?            ;Number of screen columns
  81. points        dw    ?            ;Scan lines per character
  82. cursor_mode    dw    ?            ;Cursor mode
  83. lesschars    dw    ?            ;Count of chars deleted
  84. shiftcount    dw    ?            ;Count of chars shifted
  85.  
  86. chk_case    db    0            ;1 = respect case in srches
  87. insert_cursor    db    0            ;1 = block over - line ins.
  88. insert_flag    db    0            ;0 = insert off, 1 = on
  89. multi_cmd    db    0            ;Multi cmd flag
  90. multi_switch    db    14h            ;Multi cmd sep char
  91. keys_cnt    dw    0
  92. keylist_base    dw    ?            ;Ptr to key code list
  93. cmdlist_base    dw    ?            ;Ptr to cmd list
  94.  
  95. cmdstack_base    dw    ?            ;Offset of cmd stack
  96. cmdstack_end     dw    ?            ;Offset of cmd stack end
  97.  
  98. cmdstack_headl    =    $
  99. cmdstack_head    dw    ?            ;Offset of cmd stack last cmd
  100. cmdstack_seg    dw    ?            ;segment of cmd stack buff
  101. cmdstack_curr    dw    ?            ;Offset of cmd stack curr cmd
  102.  
  103. cmdstack_size    dw    512            ;Size of command stack.
  104.                         ;  in command stack
  105. DataBlockEnd    =    $
  106. ;============================================================================
  107. ; DOSINT processes calls to interrupt 21h
  108. ;============================================================================
  109. dosint        proc    far
  110.         assume    cs:code,ds:nothing,es:nothing
  111.          cmp    ah,0ah            ;Check for char input
  112.          je    dosint_1            ;If so, continue
  113. goto_dos:
  114.         jmp    cs:[int21h]             ;else pass the call to DOS
  115. ;
  116. ;Compare the active PSP with COMMAND.COM PSP. 
  117. ;
  118. dosint_1:
  119.         push    ax            ;Save registers
  120.         push    bx
  121.         push    es
  122.         mov    ah,51h            ;Get active PSP segment
  123.         pushf
  124.         call    cs:[int21h]
  125.  
  126.         mov    es,bx            ;See if PSP is own parent.
  127.         cmp    bx,es:[16h]
  128.         je    dosint_2        ;Yes, take the call.
  129. goto_dos1:
  130.         pop    es
  131.         pop    bx            ;Cleanup and goto DOS
  132.         pop    ax
  133.         jmp    short goto_dos
  134. dosint_2:
  135.         cld                ;Set direction flag
  136.         mov    cs:[saved_ss],ss    ;Save SS:SP
  137.         mov    cs:[saved_sp],sp
  138.         cli
  139.         push    cs                      ;Move to internal stack
  140.         pop    ss
  141.         mov    sp,RES_STACK
  142.         sti
  143.         push    bp                      ;Save remaining registers.
  144.         mov    bp,sp            ;Set up stack access
  145.         push    cx
  146.         push    dx
  147.         push    di
  148.         push    si
  149.         push    ds
  150. ;
  151. ;Find environment for COMMAND.COM.  
  152. ;
  153.         mov    es,bx
  154.         mov    ax,es:[2ch]        ;Get seg of master env
  155.  
  156.         dec    ax
  157.         mov    es,ax
  158.         cmp    byte ptr es:[0],"M"    ;See if valid memory block
  159.         je    dosint_21  
  160.         mov    dx,bx            ;Save COMMAND PSP segment
  161.         dec    bx               ;Point back to mcb
  162.         mov    es,bx
  163.  
  164.         add    bx,es:[3]        ;Get size of memory block
  165.         inc    bx
  166.         cmp    es:[1],dx        ;See if owned by CMD.COM
  167.         je    dosint_21
  168.         pop    ds
  169.         pop    si
  170.         pop    di
  171.         pop    dx
  172.         pop    cx
  173.         jmp    goto_dos1
  174. dosint_21:
  175.         inc    ax
  176.         mov    cs:[cmdcom_env],ax    ;Save env
  177.         cmp    cs:multi_cmd,0        ;Check for pending multiple
  178.         je    dosint_211        ;  command.
  179.         push    ds
  180.         lds    si,cs:[temp_buff]    ;DS:SI = temp buff
  181.         xor    cx,cx
  182.         mov    cl,ds:[si]        ;Get length of saved cmd
  183.         push    cx
  184.         push    si
  185.         inc    si
  186.         call    print_string        ;Print saved cmd 
  187.         pop    si
  188.         pop    cx
  189.         pop     es            ;ES:DI = out buffer
  190.         mov    di,dx
  191.         inc    cx
  192.         jmp    dosint_71        ;Copy cmd to out buffer
  193. dosint_211:
  194. ;
  195. ;The call is from COMMAND.COM. Invoke line editor.
  196. ;
  197.         push    ds            ;Save DS
  198.         xor    ax,ax            ;Then zero it
  199.         mov    ds,ax
  200.         mov    ax,ds:[0485h]        ;Get number of scan lines
  201.         mov    cs:[points],ax        ;Record new number of scan
  202.         mov    ax,ds:[0460h]        ;  lines per character and
  203.         mov    cs:[cursor_mode],ax    ;  cursor mode
  204.         pop    ds            ;Restore DS
  205.  
  206.         push    dx
  207.         call    cmd_input        ;Call line editor
  208.         pop     dx
  209.  
  210.         mov    cx,cs:[cursor_mode]    ;Set default cursor
  211.         mov    ah,1
  212.         int    10h
  213.  
  214.         mov    ax,cs:[cmdstack_head]    ;Get head ptr
  215.         mov    cs:[cmdstack_curr],ax    ;Reset curr cmd ptr
  216.         cmp    cs:[cmdstack_size],0
  217.         je    dosint_3
  218.         mov    si,dx            ;Copy input buff ptr
  219.         inc    si            ;Move past buffer size 
  220.         mov    cl,ds:[si]        ;Get cmd length
  221.         cmp    cl,cs:[minlength]    ;See if long enough to sav
  222.         jb    dosint_3
  223.         xor    ch,ch
  224.         call    cmd_record        ;Save cmd in stack
  225.         call    srch_stack        ;See if cmd already in stk
  226.         jc    dosint_22
  227.         jnz    dosint_22
  228.         call    del_cmd            ;If so, delete stacked cmd
  229. dosint_22:
  230.         mov    cs:[cmdstack_head],di    ;Save new head ptr
  231.         mov    cs:[cmdstack_curr],di    ;Reset curr cmd ptr
  232. ;
  233. ;Check for alias before returning to COMMAND.COM
  234. ;
  235. dosint_3:
  236.         cmp    cs:[chk_alias],0         ;See if alias translation
  237.         je    dosint_8          ;  is enabled.
  238.         mov    si,dx            ;Get pointer to input buffer
  239.         inc     si
  240.         xor    cx,cx
  241.         or     cl,ds:[si]        ;Get length of buffer
  242.         je    dosint_8        ;If buffer empty, exit.
  243.         inc    si            ;Point to 1st char in buffer
  244.         push    cs
  245.         pop    es            ;Set ES to installed code.
  246.         call    searchalias        ;See if an alias is found.
  247.         jc    dosint_8        ;No, exit.
  248. ;
  249. ;If alias found, copy it from alias list to internal buffer.
  250. ;
  251.         mov     si,di            ;Load SI with alias pointer
  252.         mov    ax,es
  253.         mov    ds,ax            ;Point DS to alias list seg
  254.         xor    cx,cx
  255.         mov    cl,ds:[si+3]        ;Get size of alias
  256.         call    getalias        ;Get alias from list
  257. ;
  258. ;Append remainder of command line to alias if no cmd line parameters were used.
  259. ;
  260.         or    dx,dx            ;See if any command line
  261.         jne    dosint_6        ;  parameters were used.
  262.         push    si            ;Save pointer to buffer.
  263.         push    ds
  264.         mov    di,si
  265.         add    di,cx            ;Point DI to end of alias
  266.         mov    dx,cx            ;Save length of alias
  267.         mov    si,[bp-4]        ;Point DS:SI to command.com
  268.         mov    ds,[bp-10]        ;  data buffer.
  269.         xor    cx,cx
  270.         inc    si
  271.         mov    cl,[si]            ;Get length of command line.
  272.         cmp    ah,cl            ;See if enough space in
  273.         ja    dosint_4        ;  internal buffer. If not
  274.         mov    cl,ah            ;  copy only until buff full.
  275. dosint_4:
  276.         inc    si
  277.         mov    bl,1             ;Skip past alias.
  278.         call    scan4char           
  279.         jc    dosint_5
  280.         dec    si            ;Back up 1 char
  281.         inc    cx
  282.         add    dx,cx            ;Add length of command line.
  283.         rep    movsb            ;Copy command line
  284. dosint_5:
  285.         mov    cx,dx            ;Restore length of command
  286.         pop    ds            ;Restore pointer
  287.         pop    si
  288. ;
  289. ;Copy alias from internal buffer to COMMAND.COM data buffer.
  290. ;
  291. dosint_6:
  292.         mov    di,[bp-4]        ;Point ES:DI to command.com
  293.         mov    es,[bp-10]        ;  data buffer.
  294.         mov    dx,di
  295.         mov    al,es:[di]        ;Get size of data buffer
  296.         dec    al            ;If alias longer than buffer,
  297.         cmp    al,cl            ;  copy only the enough
  298.         ja     dosint_7        ;  characters to fill the
  299.         xor    cx,cx            ;  buffer.
  300.         mov     cl,al
  301. dosint_7:
  302.         inc    di            ;Move DI past length bytes
  303.         mov    es:[di],cl        ;Save length of command
  304. dosint_71:
  305.         inc    di
  306.         rep    movsb
  307.         mov    byte ptr es:[di],13     ;Append carriage return
  308. ;
  309. ;Check for multiple cmds on one line
  310. ;
  311. dosint_8:
  312.         mov    cs:[multi_cmd],0    ;Assume no multi cmd.
  313.         mov    ds,[bp-10]        ;DS = out buff seg
  314.  
  315.         mov    di,dx            ;ES:DI - out buff
  316.         push    ds
  317.         pop    es
  318.         inc    di            ;Move past buff size byte
  319.         xor    cx,cx
  320.         mov    cl,ds:[di]        ;Get length
  321.         jcxz    dosint_exit        ;If zero, skip
  322.         mov    bx,di            ;Copy ptr to len byte
  323.         inc    di
  324.         mov    al,cs:[multi_switch]    ;Scan for Ctrl-T
  325.         repne    scasb
  326.         jne    dosint_exit        ;No multi cmd, exit.
  327.         mov    byte ptr ds:[di-1],13
  328.         stc
  329.         sbb    ds:[bx],cl
  330.         mov    si,di
  331.         les    di,cs:[temp_buff]
  332.         mov    al,cl            ;Save length of remainder.
  333.         stosb
  334.         rep    movsb
  335.         mov    cs:[multi_cmd],1    ;Set multi cmd flag.
  336. dosint_exit:
  337.         pop    ds
  338.         pop    si
  339.         pop    di
  340.         pop    dx
  341.         pop    cx
  342.         pop    bp
  343.             cli
  344.         mov    ss,cs:[saved_ss]    ;Restore stack pointer
  345.         mov    sp,cs:[saved_sp]
  346.         sti
  347.         pop    es
  348.         pop    bx
  349.         pop    ax
  350.         iret                ;Return to COMMAND.COM
  351. dosint        endp
  352. ;----------------------------------------------------------------------------
  353. ; GETALIAS Copies an alias from the alias list while substituting any
  354. ;          environment variables and command line parameters.
  355. ; Entry:  DS:SI - pointer to alias
  356. ; Exit:   DS:SI - pointer to buffer containing translated alias.
  357. ;            AH - free space in buffer
  358. ;            CX - length of the alias
  359. ;----------------------------------------------------------------------------
  360. getalias    proc    near
  361.         mov    di,work_buff_ptr    ;Point DI to internal buffer
  362.         xor    ax,ax               ;Point to command by adding
  363.         or    al,ds:[si+2]        ;  the size of the alias to
  364.         jne    alias_0
  365.         mov    al,2
  366. alias_0:
  367.         add    si,ax               ;  pointer to the entry.
  368.         add    si,4            ;Move past list data.
  369.         mov    ah,126            ;AH contains max size of buff
  370.         xor    dx,dx            ;Clear flag for line params
  371. alias_1:
  372.         lodsb                ;Get byte from alias
  373.         cmp    al,"%"            ;See if special character
  374.         je     alias_3            ;Yes, process special char.
  375. alias_2:
  376.         stosb                ;Store byte from alias
  377.         dec    ah            ;Dec buffer size counter
  378.         jz    alias_6            ;If internal buffer full, done
  379.         loop    alias_1
  380.         jmp    short alias_6        ;If at end of alias, done
  381. ;
  382. ;A percent sign has been found indicating a 'soft' parameter.
  383. ;
  384. alias_3:
  385.         lodsb
  386.         dec    cx            
  387.         cmp    al,"%"            ;If double %, include in one
  388.         je    alias_2            ;  % in alias.
  389.                 mov    bh,al              ;If *, copy all of command
  390.         cmp    al,"*"            ;  line into alias.
  391.         je    alias_31        ;Copy and check to see if
  392.         sub    bh,"0"            ;  the next char is a number.
  393.         jb    alias_5         ;  If so, assume a line
  394.         cmp    bh,9                    ;  parameter.
  395.         ja    alias_5
  396. alias_31:
  397.          call    sublineparam        ;Substitute a line paramter
  398.         inc    dx            ;Set parameter used flag
  399. alias_4:
  400.         loop    alias_1
  401.         jmp    short alias_6        ;If at end of alias, done
  402. alias_5:
  403.         dec    si            ;Backup to 1st character
  404.         inc    cx
  405.          call    subenvvar        ;Substitute an environment var
  406.         loop    alias_1
  407. alias_6:
  408.         mov    si,work_buff_ptr    ;Point SI to internal buffer
  409.         mov    cx,di            ;Compute size of completed
  410.         sub    cx,si                     ;  alias.
  411. nop_cmd:
  412.         ret
  413. getalias    endp
  414.  
  415. ;----------------------------------------------------------------------------
  416. ; SUBLINEPARAM substitutes a parameter from the command line into the alias.
  417. ; Entry:  DS:SI - pointer to alias
  418. ;         ES:DI - pointer to buffer to copy the line parameter
  419. ;            AH - remaining space in the internal buffer
  420. ;            BH - binary number of the line parameter
  421. ;            CX - length of the alias
  422. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  423. ;         DS:SI - pointer to the character after the line parameter number
  424. ;            CX - remaining length of the alias
  425. ;----------------------------------------------------------------------------
  426. sublineparam    proc    near
  427.         push    cx
  428.         push    si
  429.         push    ds
  430.         mov    si,[bp-4]        ;Get pointer to command.com
  431.         mov    ds,[bp-10]        ;  data buffer.
  432.         xor    cx,cx
  433.         inc    si            ;Get number of chars in buffer.
  434.         mov    cl,ds:[si]        ;Point to the first byte of
  435.         inc    si            ;  data.
  436. sublineparam_1:
  437.         or    bh,bh            ;Check count of param to find.
  438.         jz    sublineparam_2
  439.         mov    bl,1
  440.         call    scan4char        ;Find next space
  441.         jc    sublineparam_exit
  442.         dec    bl
  443.         call    scan4char        ;Find next word
  444.         jc    sublineparam_exit
  445.         cmp    bh,'*'
  446.         je    sublineparam_11
  447.         dec    bh            ;Dec parameter count
  448.         jne    sublineparam_1        ;If not done, loop back.
  449. sublineparam_11:
  450.         dec    si            ;Backup to 1st char in word.
  451. sublineparam_2:
  452.         lodsb                ;Get character from parameter
  453.         cmp    bh,'*'
  454.         je    sublineparam_3
  455.         cmp    al,' '            ;If space, parameter done
  456.         jbe    sublineparam_exit
  457. sublineparam_3:
  458.         cmp    al,13            ;If CR, line done
  459.         jbe    sublineparam_exit
  460.         stosb
  461.         dec    ah            ;Dec buffer size counter
  462.         jnz    sublineparam_2
  463. sublineparam_exit:
  464.         pop    ds
  465.         pop    si
  466.         pop    cx
  467.         ret
  468. sublineparam    endp
  469.  
  470. ;----------------------------------------------------------------------------
  471. ; SUBENVVAR substitutes an environment variable into alias.
  472. ; Entry:  DS:SI - pointer to variable to substitute
  473. ;         ES:DI - pointer to buffer to copy the contents of the variable
  474. ;            AH - remaining space in internal buffer
  475. ;            CX - length of alias string
  476. ; Exit:   DS:SI - pointer to the byte after the variable name
  477. ;         ES:DI - pointer to the byte after the variable contents
  478. ;            CF - set if variable not found
  479. ;----------------------------------------------------------------------------
  480. subenvvar      proc    near
  481.         push    dx
  482.         push    ds
  483.         push    es
  484. ;
  485. ;Compute the length of the variable name.
  486. ;
  487.         mov    bx,di                    ;Save pointer to internal buff
  488.         mov    di,si                   ;Compute the length of the
  489.         mov      dx,cx                   ;  environment variable by
  490.         mov    al,"%"                  ;  searching for the trailing
  491.         repne    scasb                   ;  % sign.
  492.         je    subenvvar_0
  493.         mov    di,bx            ;If no trailing %, ignore
  494.         mov    cx,dx            ;  and continue.
  495.         jmp    short subenvvar_exit1
  496. subenvvar_0:
  497.         sub    dx,cx            ;Compute length of variable.
  498.         dec    dx            ;Subtract % byte fron length.
  499.         push    di            ;Save ptr to end of env var.
  500. ;
  501. ;Search the Master Environment block for the variable pointed to by DS:SI
  502. ;
  503.         mov    es,cs:[cmdcom_env]    ;Get segment of master env blk
  504.         xor    di,di            ;Point ES:DI to environment.
  505.         push    cx            ;Save alias size.
  506.         push    bx            ;Save ptr to internal buffer
  507.         mov     bx,si            ;Save pointer to var name
  508. subenvvar_1:
  509.         mov    si,bx            ;Get back ptr to var name.
  510.         mov    cx,dx            ;Compare env var to var in
  511.         repe    cmpsb                   ;  alias.
  512.         jne    subenvvar_11        ;Variable not found.
  513.         cmp    byte ptr es:[di],'='
  514.         je    subenvvar_2        ;Variable found, exit loop
  515. subenvvar_11:
  516.         xor    al,al            ;Find next environment var.
  517.         mov    cx,-1              ;Scan the entire segment.
  518.         repne    scasb
  519.         cmp    byte ptr es:[di],0    ;If double zero, end of env
  520.         jne    subenvvar_1        ;  block. else, loop back.
  521.         pop    di                      ;Restore DI and exit
  522.         jmp    short subenvvar_exit
  523. ;
  524. ;Environment variable found. Substitute into alias.
  525. ;
  526. subenvvar_2:
  527.         mov    si,es            ;DS:SI points to env string
  528.         mov    ds,si            ;ES:DI points to internal buff
  529.         mov     si,cs
  530.         mov    es,si
  531.         mov    si,di            ;Copy pointer to var contents.
  532.         pop    di               ;Restore ptr to internal buff
  533. subenvvar_3:
  534.         lodsb                ;Move environment pointer past
  535.         cmp    al,"="            ;  the equals sign.
  536.         jne    subenvvar_3
  537. subenvvar_4:
  538.         lodsb                ;Move pointer to first
  539.         cmp    al," "            ;  non-space character.
  540.         jb    subenvvar_4
  541. subenvvar_5:
  542.         or    al,al            ;See if at the end of variable
  543.         je    subenvvar_exit
  544.         stosb                ;Save character in command
  545.         lodsb                ;Get next character
  546.         dec    ah            ;Dec buffer size count.
  547.         jne    subenvvar_5        ;If buffer not full, continue
  548. subenvvar_exit:
  549.         pop    cx            ;Restore alias length
  550.         pop    si            ;Restore alias pointer
  551. subenvvar_exit1:
  552.         pop    es            ;Restore segment registers
  553.         pop    ds
  554.         pop    dx
  555.         ret
  556. subenvvar    endp
  557.  
  558. ;----------------------------------------------------------------------------
  559. ; SUBKEY searches the alias list for a key substitution
  560. ; Entry:  AX - key code
  561. ; Exit:   CF - clear if key found, set if not found
  562. ;         DX - offset address of matching entry in alias list (if CF = 0)
  563. ;         CX - length of matching entry (if CF = 0)
  564. ;----------------------------------------------------------------------------
  565. subkey        proc    near
  566.         push    bx
  567.         push    di
  568.         push    si
  569.         push    ds
  570.         push    es
  571.         push    cs
  572.         pop    es
  573.         call    searchkey        ;Find key in alias list
  574.         jc    subkey_exit
  575. ;
  576. ;Copy alias into internal buffer.
  577. ;
  578.         mov     si,di            ;Load SI with alias pointer
  579.         mov    ax,es
  580.         mov    ds,ax            ;Point DS to alias list seg
  581.         xor    cx,cx
  582.         mov    cl,ds:[si+3]        ;Get size of alias
  583.         call    getalias        ;Get alias from list
  584.         mov    dx,si            ;Copy pointer to buffer
  585.         clc                ;Set key found flag
  586. subkey_exit:
  587.         pop    es
  588.         pop    ds
  589.         pop    si
  590.         pop    di
  591.         pop    bx
  592.         ret
  593. subkey        endp
  594. ;-----------------------------------------------------------------------------
  595. ; SEARCHKEY searches the alias list for a matching key code.
  596. ; Entry:     AX - keycode to search for
  597. ;            ES - segment of installed code
  598. ; Exit:      CF - clear if alias found
  599. ;         ES:DI - pointer to matching entry in alias list, if CF is clear
  600. ;-----------------------------------------------------------------------------
  601. searchkey    proc    near
  602.         les    di,es:[aliaslist_ptr]    ;Get pointer to alias list.
  603. searchkey_1:
  604.         mov    dx,es:[di]        ;Get next entry offset
  605.         cmp    dx,-1            ;See if at the end of the list
  606.         stc                ;Set error flag (doesn't change
  607.         je    searchkey_exit        ;  JE test).
  608.         cmp    es:[di+4],ax        ;Check for key code.
  609.         je    searchkey_exit        ;If found, exit loop
  610. searchkey_2:
  611.         add    di,dx             ;Else, point to next entry.
  612.         jmp    short searchkey_1
  613. searchkey_exit:
  614.  
  615.         ret
  616. searchkey    endp
  617. ;-----------------------------------------------------------------------------
  618. ; SEARCHALIAS searches the alias list for a matching alias.
  619. ; Entry:  DS:SI - pointer to alias
  620. ;            ES - segment of installed code
  621. ;            CX - length input buffer
  622. ; Exit:      CF - clear if alias found
  623. ;         ES:DI - pointer to matching entry in alias list, if CF is clear
  624. ;-----------------------------------------------------------------------------
  625. searchalias    proc    near
  626.         push    bx            ;Save registers
  627.         push    cx
  628.         push    si
  629.         xor    bx,bx
  630. searchalias_1:
  631.         lodsb                           ;Compute the length of the
  632.         or     al,al                   ;  length of the alias by
  633.         je    searchalias_2             ;  finding the next space.
  634.         cmp    al," "                  ;Allow zero byte in alias
  635.         jbe    searchalias_3           ;  for function key labels.
  636. searchalias_2:
  637.         inc    bx
  638.          loop    searchalias_1
  639. searchalias_3:
  640.         pop    si
  641.         les    di,es:[aliaslist_ptr]    ;Get pointer to alias list.
  642.         mov    cx,bx            ;Get length of alias
  643. searchalias_4:
  644.         mov    bx,es:[di]
  645.         cmp    bx,-1            ;See if at the end of the list
  646.         je    searchalias_notfound
  647.         cmp    es:[di+2],cl        ;Compare lengths
  648.         jne    searchalias_5
  649.         push    cx            ;Save size and starting
  650.         push    di                      ;  pointers.
  651.         push    si
  652.         add    di,4            ;Point to start of alias field.
  653.         repe    cmpsb            ;Compare alias to input string
  654.         pop    si
  655.         pop    di
  656.         pop    cx
  657.         je    searchalias_6        ;If found, exit loop
  658. searchalias_5:
  659.         add    di,bx            ;Else, point to next entry.
  660.         jmp    short searchalias_4
  661. searchalias_6:
  662.         clc                ;Set alias found flag
  663. searchalias_exit:
  664.         pop    cx
  665.         pop    bx
  666.         ret
  667. searchalias_notfound:
  668.         stc
  669.         jmp    short searchalias_exit
  670. searchalias    endp
  671.  
  672. ;-----------------------------------------------------------------------------
  673. ; SCAN4CHAR scans a string to find the first character.
  674. ; Entry:  SI - pointer to ASCII string
  675. ;         BL - 0 = find next char, 1 = find next space
  676. ;         CX - file length
  677. ; Exit:   AL - first nonspace character
  678. ;         CF - set if carriage return found
  679. ;-----------------------------------------------------------------------------
  680. scan4char      proc near
  681.         assume    ds:nothing,es:nothing
  682. scan4loop:
  683.         jcxz    scan4_eol        ;See if at the end of the file.
  684.         lodsb
  685.         dec    cx                 ;Decrement file length counter.
  686.         cmp    al,13            ;Check for carriage return.
  687.         jne    scan4_1
  688. scan4_eol:
  689.         stc
  690.         jmp    short scan4_exit1
  691. scan4_1:
  692.         or    bl,bl            ;Check if searching for space
  693.         jne    scan4_2            ;  or character.
  694.         cmp    al," "            ;Check for space or other
  695.         jbe    scan4loop        ;  'white' characters.
  696.         jmp    short scan4_exit
  697. scan4_2:
  698.         cmp    al," "            ;Check for characters.
  699.         ja    scan4loop
  700. scan4_exit:
  701.         clc
  702. scan4_exit1:
  703.          ret
  704. scan4char    endp
  705.  
  706. ;----------------------------------------------------------------------------
  707. ; CMD_INPUT replaces DOS' 0Ah text input function.
  708. ; Entry: DS:DX - Ptr to input buffer
  709. ;----------------------------------------------------------------------------
  710. cmd_input    proc    near
  711.         call    set_cursor        ;Set cursor mode
  712.  
  713.         mov    ah,15            ;Get video page and columns
  714.         int    10h
  715.         dec    ah            ;Calculate max column number
  716.         mov    cs:[columns],ah        ;Save it
  717.         mov    ax,ds            ;Point ES:DI to buffer
  718.         les    di,temp_buff
  719.         mov    byte ptr es:[di],0    ;Zero search buffer
  720.         mov    es,ax
  721.         mov    di,dx
  722.         add    di,2
  723.         mov    si,dx            ;Point DS:SI to character cnt
  724.         inc    si
  725.         mov    byte ptr [si],0        ;Zero initial count
  726.         mov    cs:[bufferptr],1    ;Set initial index value
  727. ;
  728. ;Wait for a keycode to appear in the keyboard buffer.
  729. ;
  730. cmd_2:
  731.         call    getkey            ;Read a key
  732.         call    srch4cmd        ;See if key in cmd list. If
  733.         jne    cmd_3            ;  not found, print it.
  734.          call    cx            ;Call handling routine
  735.          jmp    short cmd_2        ;Return to input loop
  736. cmd_3:
  737.          call    printchar        ;Call print char routine
  738.          jmp    short cmd_2        ;Return to input loop
  739. cmd_input    endp
  740.  
  741. ;----------------------------------------------------------------------------
  742. ; GETKEY Returns keycode and shift status from keyboard.
  743. ; Exit:  AX - Keycode and shift status
  744. ;----------------------------------------------------------------------------
  745. getkey        proc    near
  746.         push    dx
  747.         push    di
  748.         push    es
  749.         mov    ax,40h            ;BIOS data seg
  750.         mov    es,ax
  751. getkey_1:
  752.         mov    ah,6            ;Get keycode
  753.         mov    dl,0ffh
  754.         int    21h
  755.         jne    getkey_2        ;Yes, then go get it
  756.         
  757.         mov    al,es:[6dh]        ;Get 2nd byte of timer ctr
  758.         and    al,0fch
  759.         cmp    al,cs:[last_click]    ;See if same 64 second
  760.         je    getkey_11        ;  incriment.
  761.         mov    cs:[last_click],al    ;Every 16 seconds, call
  762.         mov    ah,2ch            ;  DOS Get Time.  Do this
  763.         int    21h            ;  to reset 24 hr flag.
  764. getkey_11:        
  765.         int    28h            ;No, then execute int 28h
  766.         cmp    cs:win_enhanced,0
  767.         je    getkey_1
  768.         mov    ax,4680h        ;Free timeslice
  769.         int    2fh
  770.         jmp    short getkey_1        ;Loop back for another try
  771. getkey_2:
  772.         xor    ah,ah
  773.         or    al,al            ;Is it an extended code?
  774.         jne    getkey_3        ;No, then branch
  775.         mov    ah,6            ;Yes, read extended char
  776.         int    21h
  777.         mov    ah,80h            ;Set ext char flag
  778. getkey_3:
  779.         mov    dl,es:[17h]
  780.         test    dl,3            ;If one shift key pressed,
  781.         jz    getkey_4        ;  mark both.
  782.         or    dl,3
  783. getkey_4:
  784.         and    dl,0fh            ;Look only at shift bits
  785.         or    ah,dl            ;Combine shift with char
  786.         pop    es
  787.         pop    di
  788.         pop    dx
  789.         ret
  790. getkey        endp
  791. ;----------------------------------------------------------------------------
  792. ; SRCH4CMD Searchs the key list for matching key
  793. ; Entry:  AX - Key code
  794. ; Exit:   ZF - Set if key found
  795. ;         CX - Offset of cmd routine if key found
  796. ;----------------------------------------------------------------------------
  797. srch4cmd    proc    near
  798.         assume    cs:code,ds:nothing
  799.         push    es
  800.         push    di
  801.          push    cs            ;Point ES:DI to list of
  802.          pop    es            ;  supported keycodes
  803.          mov    di,keylist_base
  804.          mov    cx,keys_cnt
  805.          repne    scasw            ;Scan list of keys.
  806.         jne    srch4cmd_exit
  807.         not    cx
  808.         add    cx,keys_cnt
  809.          shl    cx,1
  810.          mov    di,cx            ;Get entry address from table
  811.          add    di,cmdlist_base
  812.          mov    cx,cs:[di]
  813.         cmp    ax,ax            ;Set ZF
  814. srch4cmd_exit:
  815.          pop    di            ;Clear the stack
  816.          pop    es
  817.         ret
  818. srch4cmd    endp
  819. ;----------------------------------------------------------------------------
  820. ; SHIFT_KEY Allows double key combinations
  821. ; Entry:  DS:SI - input buffer address
  822. ;----------------------------------------------------------------------------
  823. shift_key    proc    near
  824.         assume    cs:code,ds:nothing
  825. shift1_key:
  826.         mov    ch,40h
  827.         jmp    short shift_key_1
  828. shift2_key:
  829.         mov    ch,20h
  830.         jmp    short shift_key_1
  831. shift3_key:
  832.         mov    ch,10h
  833. shift_key_1:
  834.         call    getkey            ;Read a key
  835.         or    ah,ch            ;Add shift component
  836.         call    srch4cmd
  837.         jne    shift_key_2        ;No match, exit
  838.         jmp    cx            ;Jmp due to Enter cmd.
  839. shift_key_2:
  840.         ret
  841. shift_key    endp
  842. ;----------------------------------------------------------------------------
  843. ; ALIAS_STR displays an alias string in place of a key
  844. ; Entry:  DS:SI - input buffer address
  845. ;            AX - Key code entered
  846. ;----------------------------------------------------------------------------
  847. alias_str    proc    near
  848.         assume    cs:code,ds:nothing
  849.         call    subkey            ;Scan alias list for match
  850.         jc    alias_str_exit        ;Exit if no match found
  851. alias_str_1:
  852.         push    si
  853.         mov    si,dx            ;Copy offset address into SI
  854.         mov    al,byte ptr cs:[si]    ;Get next character
  855.         pop    si
  856.         cmp    al,13            ;If end of subparam is CR,
  857.         jne    alias_str_2        ;  then exit and execute cmd.
  858. ;Don't push-pop params around this routine.  The enter procedure does not
  859. ;return from its call!
  860.         jmp    enter
  861. alias_str_2:
  862.         inc    dx
  863.         push    cx
  864.         push    dx
  865.         call    printchar        ;Print it
  866.         pop    dx
  867.         pop    cx
  868.         jc    alias_str_exit
  869.         loop    alias_str_1          ;Loop until done
  870. alias_str_exit:
  871.         clc
  872.         ret
  873. alias_str    endp
  874. ;----------------------------------------------------------------------------
  875. ; PICK_STACK directly selects a stacked command by number
  876. ; Entry:  DS:SI - input buffer address
  877. ;----------------------------------------------------------------------------
  878. pick_stack    proc    near
  879.         push    di
  880.         push    es
  881.  
  882.         push    cs
  883.         pop    es
  884.         mov    di,offset pick_prompt    ;Display prompt
  885.         call    write_command
  886.         xor    cx,cx
  887. pick_1:
  888.         call    getkey
  889.         cmp    al,13            ;Check for Enter
  890.         je    pick_2
  891.         cmp    al,27            ;Check for Esc
  892.         je    pick_11
  893.         mov    dl,al
  894.         sub    dl,30h            ;Convert num from ASCII
  895.         jb    pick_1
  896.         cmp    dl,9
  897.         ja    pick_1
  898.         push    cx
  899.         push    dx
  900.         call    printchar
  901.         pop    dx
  902.         pop    cx
  903.         mov    al,10            ;CL = CL * 10 + DL
  904.         mul    cl
  905.         mov    cx,ax
  906.         add    cl,dl
  907.         jmp    short pick_1
  908. pick_11:
  909.         xor    cx,cx            ;Clear number
  910. pick_2:
  911.         push    cx
  912.         call    clear_line
  913.         pop    cx
  914.         jcxz    pick_exit        ;See if number = 0.
  915.         mov    es,cs:[cmdstack_seg]    ;Get ptr to head of stack
  916.         mov    di,cs:[cmdstack_head]
  917. pick_3:
  918.         call    get_prev        ;Get ptr to prev command
  919.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  920.         je    pick_exit        ;Yes, exit
  921.         loop    pick_3
  922.         call    write_command        ;Copy cmd
  923.         add    sp,4            ;Keep new ES:DI
  924.         jmp    short pick_exit1
  925. pick_exit:
  926.         pop    es
  927.         pop    di
  928. pick_exit1:
  929.         ret
  930. pick_stack    endp
  931. ;----------------------------------------------------------------------------
  932. ; DUMP_STACK displays the contents of the command stack
  933. ; Entry:  DS:SI - input buffer address
  934. ;----------------------------------------------------------------------------
  935. dump_stack    proc    near
  936.         assume    cs:code,ds:nothing
  937.         push    di
  938.         push    es
  939.         mov    es,cs:[cmdstack_seg]    ;Get ptr to head of stack
  940.         mov    di,cs:[cmdstack_head]
  941.         mov    cx,1
  942. dump_stack_1:
  943.         call    get_prev        ;Get ptr to prev command
  944.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  945.         je    dump_stack_exit        ;Yes, exit
  946.         cmp    byte ptr es:[di],0    ;See if no commands
  947.         je    dump_stack_exit        ;Yes, exit
  948.         call    new_line
  949.         mov    ax,cx            ;Print number
  950.         call    hex2asc
  951.         mov    al,':'
  952.         call    print_char
  953.         mov    al,' '
  954.         call    print_char
  955.         push    di
  956.         inc    di
  957. dump_stack_2:
  958.         mov    al,es:[di]        ;Print stacked command
  959.         inc    di
  960.         call    chk_buffend
  961.         or    al,al
  962.         je    dump_stack_3
  963.         call    print_char
  964.         jmp    short dump_stack_2
  965. dump_stack_3:
  966.         pop    di
  967.         inc    cx
  968.         jmp    dump_stack_1
  969. dump_stack_exit:
  970.         pop    es
  971.         pop    di
  972.         mov    byte ptr ds:[si],0    ;Reset count
  973.         lea    di,[si+1]        ;Reset char ptr
  974.         jmp    enter            ;Force to get new prompt
  975. dump_stack    endp
  976. ;----------------------------------------------------------------------------
  977. ; CLR_STACK empties the command stack.
  978. ; Entry:  DS:SI - input buffer address
  979. ;----------------------------------------------------------------------------
  980. clr_stack    proc    near
  981.         assume    cs:code,ds:nothing
  982.         push    di
  983.         push    es
  984.         mov    es,cs:[cmdstack_seg]    ;Get start of buffer
  985.         mov    di,cs:[cmdstack_base]
  986.  
  987.         mov    cs:[cmdstack_head],di    ;Reset pointers
  988.         mov    cs:[cmdstack_curr],di
  989.  
  990.         mov    cx,cs:[cmdstack_size]
  991.         xor    ax,ax
  992.         rep    stosb            ;Write zeros to buffer
  993.         pop    es
  994.         pop    di
  995.         clc
  996.         ret
  997. clr_stack    endp
  998. ;----------------------------------------------------------------------------
  999. ; CLR_CMD clears the command line and resets the cmd stack ptr.
  1000. ; Entry:  DS:SI - input buffer address
  1001. ;----------------------------------------------------------------------------
  1002. clr_cmd        proc    near
  1003.         assume    cs:code,ds:nothing
  1004.         call    clear_line        ;Clear cmd line
  1005.         push    di
  1006.         mov    di,cs:[cmdstack_head]    ;Reset curr stack ptr
  1007.         mov    cs:[cmdstack_curr],di
  1008.         pop    di
  1009.         clc
  1010.         ret
  1011. clr_cmd        endp
  1012. ;----------------------------------------------------------------------------
  1013. ; CLR_ALIASES empties the alias buffer.
  1014. ; Entry:  DS:SI - input buffer address
  1015. ;----------------------------------------------------------------------------
  1016. clr_aliases    proc    near
  1017.         assume    cs:code,ds:nothing
  1018.         push    di
  1019.         push    si
  1020.         push    ds
  1021.         push    es
  1022.         lds    di,aliaslist_ptr
  1023.         push    ds
  1024.         pop    es
  1025. clr_aliases_1:
  1026.         cmp    word ptr ds:[di],-1    ;See if end of list
  1027.         je    clr_aliases_3
  1028.         cmp    byte ptr ds:[di+2],0    ;See if entry a key entry
  1029.         je    clr_aliases_2
  1030.         push    di
  1031.         call    delete_aliasent        ;No, delete it.
  1032.         pop    di
  1033.         jmp    short clr_aliases_1
  1034. clr_aliases_2:
  1035.         add    di,ds:[di]        ;Point to next entry
  1036.         jmp    short clr_aliases_1
  1037. clr_aliases_3:
  1038.         clc
  1039.         pop    es
  1040.         pop    ds
  1041.         pop    si
  1042.         pop    di
  1043.         ret
  1044. clr_aliases    endp
  1045. ;----------------------------------------------------------------------------
  1046. ; BEEP_CMD attempts to beep the speaker
  1047. ; Entry:  DS:SI - input buffer address
  1048. ;----------------------------------------------------------------------------
  1049. beep_cmd    proc    near
  1050.         assume    cs:code,ds:nothing
  1051.         mov    ax,0e07h        ;BIOS print char: BEEP
  1052.         int    10h
  1053.         ret
  1054. beep_cmd    endp
  1055. ;----------------------------------------------------------------------------
  1056. ; ABORT_CMD ends and editing call and returns a zero buffer.
  1057. ; Entry:  DS:SI - input buffer address
  1058. ;----------------------------------------------------------------------------
  1059. abort_cmd    proc    near
  1060.         assume    cs:code,ds:nothing
  1061.         call    clear_line        ;Remove current cmd
  1062.         jmp    enter            ;Force return
  1063. abort_cmd    endp
  1064. ;----------------------------------------------------------------------------
  1065. ; PREV1_CMD outputs the previous command in the command stack.
  1066. ; Entry:  DS:SI - input buffer address
  1067. ;----------------------------------------------------------------------------
  1068. prev1_cmd    proc    near
  1069.         assume    cs:code,ds:nothing
  1070.         mov    cl,1
  1071.         jmp    short prev_cmd_2nd_entry
  1072. prev1_cmd    endp
  1073. ;----------------------------------------------------------------------------
  1074. ; PREV_CMD outputs the previous matching command in the command stack.
  1075. ; Entry:  DS:SI - input buffer address
  1076. ;----------------------------------------------------------------------------
  1077. prev_cmd    proc    near
  1078.         assume    cs:code,ds:nothing
  1079.         xor    cx,cx
  1080. prev_cmd_2nd_entry:
  1081.         push    bp
  1082.         mov    bp,sp
  1083.         sub    sp,2
  1084.         mov    [bp-2],cx
  1085.         cmp    cs:[cmdstack_size],0    ;See if stack enabled
  1086.         je    prev_cmd_exit1
  1087.         push    di
  1088.         push    es
  1089.         mov    di,cs:[cmdstack_curr]    ;See if at bottom of stack
  1090.         cmp    di,cs:[cmdstack_head]    ;If so, save cmd template
  1091.         jne    prev_cmd_0
  1092.  
  1093.         push    si            ;If at bottom of list, save
  1094.         xor    cx,cx            ;  search template.
  1095.         or    cl,ds:[si]
  1096.         call    cmd_record
  1097.         pop    si
  1098. prev_cmd_0:
  1099.         mov    es,cs:[cmdstack_seg]    ;Get ptr to head of stack
  1100.         mov    di,cs:[cmdstack_curr]
  1101. prev_cmd_1:
  1102.         call    get_prev        ;Get ptr to prev command
  1103.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  1104.         je    prev_cmd_exit        ;Yes, exit
  1105.         cmp    byte ptr [bp-2],0
  1106.         jne    prev_cmd_2
  1107.         call    cmp_cmdlines        ;No, see if cmd matches
  1108.         jne    prev_cmd_1        ;No match, keep looking
  1109. prev_cmd_2:
  1110.         mov    cs:[cmdstack_curr],di    ;Set new cmd stack ptr
  1111.         call    write_command        ;Match, copy cmd
  1112.         add    sp,4
  1113.         jmp    short prev_cmd_exit1
  1114. prev_cmd_exit:
  1115.         pop    es
  1116.         pop    di
  1117. prev_cmd_exit1:
  1118.         mov    sp,bp
  1119.         pop    bp
  1120.         ret
  1121. prev_cmd    endp
  1122. ;----------------------------------------------------------------------------
  1123. ; NEXT_CMD outputs the next command in the command stack.
  1124. ; Entry:  DS:SI - input buffer address
  1125. ;----------------------------------------------------------------------------
  1126. next_cmd    proc    near
  1127.         assume    cs:code,ds:nothing
  1128.         push    di
  1129.         push    es
  1130.         cmp    cs:[cmdstack_size],0    ;See if stack enabled
  1131.         je    next_cmd_exit
  1132.         mov    es,cs:[cmdstack_seg]    ;Get ptr to head of stack
  1133.         mov    di,cs:[cmdstack_curr]
  1134. next_cmd_1:
  1135.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  1136.         je    short next_cmd_2    ;Yes, exit
  1137.         call    get_next
  1138.         call    cmp_cmdlines        ;No, see if cmd matches
  1139.         jne    next_cmd_1        ;No match, keep looking
  1140. next_cmd_2:
  1141.         mov    cs:[cmdstack_curr],di    ;Set new cmd stack ptr
  1142.         call    write_command
  1143.         add    sp,4            ;Keep ES:DI from write_cmd
  1144.         jmp    short next_cmd_exit1    ;  routine and exit.
  1145. next_cmd_exit:
  1146.         pop    es
  1147.         pop    di
  1148. next_cmd_exit1:
  1149.         ret
  1150. next_cmd    endp
  1151. ;------------------------------------------------------------------------------
  1152. ; TOGGLE_INS toggles the insert flag.
  1153. ;------------------------------------------------------------------------------
  1154. toggle_ins    proc    near
  1155.         xor    cs:[insert_flag],1    ;Toggle insert flag
  1156.         call    set_cursor        ;Set cursor mode
  1157.         ret
  1158. toggle_ins    endp
  1159. ;------------------------------------------------------------------------------
  1160. ; ENTER Completes command and exits getkey loop
  1161. ; Warning:  This routine does *not* return to the routine that called it!
  1162. ;------------------------------------------------------------------------------
  1163. enter        proc    near
  1164.         call    eol            ;Place cursor at end-of-line
  1165.         mov    al,13
  1166.         mov    es:[di],al        ;Insert carriage return code
  1167.         call    print_char
  1168.         add    sp,2            ;Pop off return to getkey
  1169.         ret
  1170. enter        endp
  1171. ;------------------------------------------------------------------------------
  1172. ; TAB tabs to the next tab boundary.
  1173. ;------------------------------------------------------------------------------
  1174. tab        proc    near
  1175.         mov    al,cs:[bufferptr]    ;Calculate number of
  1176.         dec    al            ;  spaces to insert for
  1177.         xor    ah,ah            ;  soft tab
  1178.         mov    bl,8
  1179.         div    bl
  1180.         mov    cx,8
  1181.         sub    cl,ah
  1182. tab1:
  1183.         push    cx            ;Print spaces
  1184.         mov    ax,32
  1185.         call    printchar
  1186.         pop    cx
  1187.         jc    tab_exit
  1188.         loop    tab1
  1189. tab_exit:
  1190.         ret
  1191. tab        endp
  1192.  
  1193. ;------------------------------------------------------------------------------
  1194. ; BACKSPACE deletes the character left of the cursor.
  1195. ;------------------------------------------------------------------------------
  1196. backspace    proc    near
  1197.         cmp    cs:[bufferptr],1    ;At beginning of command line?
  1198.         je    bs_exit            ;Yes, then ignore it
  1199.         mov    cl,[si]            ;Get count
  1200.         sub    cl,cs:[bufferptr]    ;Calculate distance to end-of-line
  1201.         inc    cl
  1202.         xor    ch,ch
  1203.         push    cx            ;Save it
  1204.         jcxz    bs1            ;Branch if at end-of-line
  1205. ;
  1206. ;Shift all characters right of the cursor in the buffer one slot left.
  1207. ;
  1208.         push    si            ;Save SI and DI
  1209.         push    di
  1210.         mov    si,di            ;Position them for shifts
  1211.         dec    di
  1212.         rep    movsb            ;Shift characters right of cursor
  1213.         pop    di            ;Restore registers
  1214.         pop    si
  1215. ;
  1216. ;Display the new string and update input parameters.
  1217. ;
  1218. bs1:
  1219.         call    move_left        ;Move cursor left
  1220. bs2:
  1221.         pop    cx            ;Retrieve shift count
  1222.         push    si            ;Save SI
  1223.         mov    si,di            ;Point SI to new part of string
  1224.         call    print_string        ;Print the new part
  1225.         mov    al,32
  1226.         call    print_char        ;Blank the last character
  1227.         pop    si            ;Restore registers
  1228.         mov    ah,2            ;Reset the cursor
  1229.         int    10h
  1230.         dec    byte ptr [si]        ;Decrement character count
  1231. bs_exit:
  1232.         ret
  1233. backspace    endp
  1234.  
  1235. ;------------------------------------------------------------------------------
  1236. ; PRINTCHAR writes a new character to the input buffer and echoes it.
  1237. ; Entry:  AX - character to print
  1238. ; Exit:   CF clear if character printed
  1239. ;         CF set if buffer full
  1240. ;------------------------------------------------------------------------------
  1241. printchar    proc    near
  1242.         cmp    ah,80h            ;Don't print non-standard
  1243.         je    print0            ;  chars.
  1244.         cmp    al,7fh
  1245.         je    print0
  1246.         cmp    al,20h            ;Don't display control
  1247.         jae    print01            ;  chars.
  1248. print0:
  1249.         mov    al,4
  1250. print01:
  1251.         cmp    cs:[insert_flag],0    ;Insert state on?
  1252.         jne    print3            ;Yes, then branch
  1253. ;
  1254. ;Print a character in overstrike mode.
  1255. ;
  1256.         mov    cl,[si]            ;Get count
  1257.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1258.         jae    print2            ;No, then branch
  1259.         mov    cl,[si-1]        ;Get maximum length
  1260.         sub    cl,[si]            ;Subtract current length
  1261.         cmp    cl,1            ;Buffer full?
  1262.         je    beep            ;Yes, then branch
  1263. print1:
  1264.         inc    byte ptr [si]        ;Increment count
  1265. print2:
  1266.         stosb                ;Deposit new character
  1267.         call    print_char        ;Then print it
  1268.         inc    cs:[bufferptr]        ;Advance buffer pointer
  1269. print_exit:
  1270.         clc                ;Clear CF and exit
  1271.         ret
  1272. beep:
  1273.         mov    ax,0E07h        ;Print ASCII 7 thru BIOS
  1274.         int    10h
  1275.         stc
  1276.         ret
  1277. ;
  1278. ;Print a character in insert mode.
  1279. ;
  1280. print3:
  1281.         mov    cl,[si-1]        ;Get maximum length
  1282.         sub    cl,[si]            ;Subtract current count
  1283.         cmp    cl,1            ;Buffer full?
  1284.         je    beep            ;Yes, then branch
  1285.         mov    cl,[si]            ;Get count
  1286.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1287.         jb    print1            ;Yes, then branch
  1288.         sub    cl,cs:[bufferptr]    ;Calculate number of shifts
  1289.         inc    cl
  1290.         xor    ch,ch
  1291.         push    cx            ;Save shift count
  1292.         push    si            ;Save SI
  1293.         add    di,cx            ;Position DI to end-of-line
  1294.         mov    si,di            ;Position SI just before it
  1295.         dec    si
  1296.         std                ;Set DF for now
  1297.         rep    movsb            ;Make room for new character
  1298.         cld                ;Clear DF
  1299.         pop    si            ;Restore SI
  1300.         mov    es:[di],al        ;Deposit new character
  1301.         mov    ah,3            ;Get cursor position
  1302.         int    10h
  1303.         pop    cx            ;Retrieve shift count
  1304.         inc    cx            ;Increment it
  1305.         push    dx            ;Save cursor position
  1306.         push    si            ;Save SI
  1307.         mov    si,di            ;Point SI to current location
  1308.         call    print_string        ;Print new part of string
  1309.         pop    si            ;Restore SI and DX
  1310.         pop    dx
  1311.         mov    ah,2            ;Reset cursor position
  1312.         int    10h
  1313.         inc    byte ptr [si]        ;Add to character count
  1314.         call    move_right        ;Move cursor right
  1315.         jmp    print_exit
  1316. printchar    endp
  1317.  
  1318. ;------------------------------------------------------------------------------
  1319. ; DELETE deletes the character at the cursor.
  1320. ;------------------------------------------------------------------------------
  1321. delete        proc    near
  1322.         mov    cl,[si]            ;Get count
  1323.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1324.         jb    del2            ;Yes, then ignore keypress
  1325.         sub    cl,cs:[bufferptr]    ;Calculate number of shifts
  1326.         xor    ch,ch            ;Byte to word in CX
  1327.         push    cx            ;Save shift count
  1328.         jcxz    del1            ;Branch if no shifts
  1329.         push    si            ;Save SI and DI
  1330.         push    di
  1331.         mov    si,di            ;Position registers for shift
  1332.         inc    si
  1333.         rep    movsb            ;Shift chars right of cursor
  1334.         pop    di            ;Restore registers
  1335.         pop    si
  1336. del1:
  1337.         mov    ah,3            ;Get cursor position
  1338.         int    10h
  1339.         jmp    bs2            ;Exit thru BACKSPACE routine
  1340. del2:
  1341.         ret
  1342. delete        endp
  1343.  
  1344. ;------------------------------------------------------------------------------
  1345. ; CTRL_BS deletes the word at the cursor.
  1346. ;------------------------------------------------------------------------------
  1347. ctrl_bs        proc    near
  1348.         xor    cx,cx            ;Exit now if there is nothing
  1349.         or     cl,[si]            ;  on the command line
  1350.         jnz    cbs1
  1351. cbs_exit:
  1352.         ret
  1353. cbs1:
  1354.         cmp    cs:[bufferptr],1    ;Exit if the cursor is at the
  1355.         je    cbs3            ;  at the end of the command
  1356.         cmp    cl,cs:[bufferptr]    ;  line or if it is under a
  1357.         jb    cbs_exit        ;  space; otherwise, move to
  1358.         cmp    byte ptr [di],32    ;  the beginning of the
  1359.         je    cbs_exit        ;  current word
  1360.         cmp    byte ptr [di-1],32
  1361.         je    cbs3
  1362. cbs2:
  1363.         push    cx            ;Save CX
  1364.         call    ctrl_left        ;Move to start of word
  1365.         pop    cx            ;Restore CX
  1366. cbs3:
  1367.         inc    cx            ;Calculate max number of
  1368.         push    cx            ;  characters to search
  1369.         mov    dl,cs:[bufferptr]    ;  looking for the next
  1370.         xor    dh,dh            ;  word or end-of-line
  1371.         sub    cx,dx
  1372.         push    di            ;Save DI
  1373. cbs4:
  1374.         inc    di            ;Search until DI addresses
  1375.         cmp    byte ptr [di],32    ;  either the first character
  1376.         je    cbs5            ;  in the next word or the
  1377.         cmp    byte ptr [di-1],32    ;  end of the command line
  1378.         je    cbs6
  1379. cbs5:
  1380.         loop    cbs4
  1381. cbs6:
  1382.         mov    dx,di            ;Save final value of DI
  1383.         pop    di            ;Restore DI
  1384.         pop    cx            ;Retrieve count
  1385.         mov    cs:[lesschars],dx    ;Calculate number of chars to
  1386.         sub    cs:[lesschars],di    ;  be deleted
  1387.         sub    cx,dx            ;Then calculate how many chars
  1388.         add    cx,si            ;  must be shifted
  1389.         mov    cs:[shiftcount],cx
  1390.         jcxz    cbs7            ;Branch if no shift
  1391.         push    si            ;Save registers
  1392.         push    di
  1393.         mov    si,dx            ;Point DS:SI to next word
  1394.         rep    movsb            ;Delete current word
  1395.         pop    di            ;Restore registers
  1396.         pop    si
  1397. cbs7:
  1398.         mov    cx,cs:[lesschars]    ;Update character counter
  1399.         sub    [si],cl            ;  in input buffer
  1400.         mov    ah,3            ;Save the current cursor
  1401.         int    10h            ;  position on the stack
  1402.         push    si            ;Update the text on the
  1403.         mov    si,di            ;  command line
  1404.         mov    cx,cs:[shiftcount]
  1405.         call    print_string
  1406.         pop    si
  1407.         mov    cx,cs:[lesschars]
  1408. cbs8:
  1409.         mov    al,32            ;Print as many spaces as
  1410.         call    print_char        ;  there were characters
  1411.         loop    cbs8            ;  deleted
  1412.         mov    ah,2            ;Restore cursor position
  1413.         int    10h            ;  and exit
  1414.         ret
  1415. ctrl_bs        endp
  1416. ;------------------------------------------------------------------------------
  1417. ; CTRL_END deletes command line text from the cursor to the end of the line.
  1418. ;------------------------------------------------------------------------------
  1419. ctrl_end    proc    near
  1420.         mov    cl,[si]            ;Exit if already at end
  1421.         cmp    cl,cs:[bufferptr]    ;  of line
  1422.         jb    ce_exit
  1423.         sub    cl,cs:[bufferptr]    ;Calculate number of chars
  1424.         xor    ch,ch            ;  to be deleted
  1425.         inc    cx
  1426.         sub    [si],cl            ;Update count in input buffer
  1427.         push    cx
  1428.         mov    ah,3            ;Get and save cursor position
  1429.         int    10h
  1430.         pop    cx
  1431. ce1:
  1432.         mov    al,32            ;Print as many spaces as
  1433.         call    print_char        ;  there are characters
  1434.         loop    ce1            ;  to delete
  1435.         mov    ah,2            ;Reset cursor position
  1436.         int    10h
  1437. ce_exit:
  1438.         ret
  1439. ctrl_end    endp
  1440. ;------------------------------------------------------------------------------
  1441. ; MOVE_LEFT moves the cursor one character left.
  1442. ;------------------------------------------------------------------------------
  1443. move_left    proc    near
  1444.         cmp    cs:[bufferptr],1    ;At beginning of line?
  1445.         je    left2            ;Yes, then ignore keypress
  1446.         mov    ah,3            ;Get cursor position
  1447.         int    10h
  1448.         dec    dl            ;Decrement it by 1
  1449.         cmp    dl,0FFh
  1450.         jne    left1
  1451.         mov    dl,cs:[columns]        ;Decrement row number by 1
  1452.         dec    dh            ;  if cursor wraps around
  1453. left1:
  1454.         mov    ah,2            ;Set new position
  1455.         int    10h
  1456.         dec    di            ;Decrement pointers
  1457.         dec    cs:[bufferptr]
  1458. left2:
  1459.         ret
  1460. move_left    endp
  1461. ;------------------------------------------------------------------------------
  1462. ; MOVE_RIGHT moves the cursor one character right.
  1463. ;------------------------------------------------------------------------------
  1464. move_right    proc    near
  1465.         mov    cl,[si]            ;Get count
  1466.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1467.         jb    rt2            ;Yes, then ignore keypress
  1468.         mov    ah,3            ;Get cursor position
  1469.         int    10h
  1470.         inc    dl            ;Increment column number
  1471.         cmp    dl,cs:[columns]        ;Increment row number if
  1472.         jna    rt1            ;  cursor wraps around
  1473.         xor    dl,dl
  1474.         inc    dh
  1475. rt1:
  1476.         mov    ah,2            ;Position cursor
  1477.         int    10h
  1478.         inc    di            ;Advance pointers
  1479.         inc    cs:[bufferptr]
  1480. rt2:
  1481.         ret
  1482. move_right    endp
  1483. ;------------------------------------------------------------------------------
  1484. ; CTRL_LEFT moves the cursor one word left.
  1485. ;------------------------------------------------------------------------------
  1486. ctrl_left    proc    near
  1487.         call    move_left        ;Move one character left
  1488.         cmp    cs:[bufferptr],1    ;Beginning of line?
  1489.         je    cl_exit            ;Yes, then exit
  1490.         cmp    byte ptr es:[di],32    ;Loop back if current char
  1491.         je    ctrl_left        ;  is a space
  1492.         cmp    byte ptr es:[di-1],32    ;Loop back if char to the
  1493.         jne    ctrl_left        ;  left is not a space
  1494. cl_exit:
  1495.         ret
  1496. ctrl_left    endp
  1497. ;------------------------------------------------------------------------------
  1498. ; CTRL_RIGHT moves the cursor one word right.
  1499. ;------------------------------------------------------------------------------
  1500. ctrl_right    proc    near
  1501.         call    move_right        ;Move one character right
  1502.         mov    cl,[si]            ;End-of-line?
  1503.         cmp    cl,cs:[bufferptr]    ;Yes, then exit
  1504.         jb    cr_exit
  1505.         cmp    byte ptr es:[di],32    ;Loop back if current char
  1506.         je    ctrl_right        ;  is a space
  1507.         cmp    byte ptr es:[di-1],32    ;Loop back if char to the
  1508.         jne    ctrl_right        ;  left is not a space
  1509. cr_exit:
  1510.         ret
  1511. ctrl_right    endp
  1512. ;------------------------------------------------------------------------------
  1513. ; HOME relocates the cursor to the beginning of the command line.
  1514. ;------------------------------------------------------------------------------
  1515. home        proc    near
  1516.         mov    cl,cs:[bufferptr]    ;Get position pointer
  1517.         dec    cl            ;Calculate distance from start
  1518.         xor    ch,ch
  1519.         jcxz    home_exit        ;Exit if already there
  1520. home1:
  1521.         push    cx            ;Save count
  1522.         call    move_left        ;Move left one space
  1523.         pop    cx            ;Retrieve count
  1524.         loop    home1            ;Loop until done
  1525. home_exit:
  1526.         ret
  1527. home        endp
  1528. ;------------------------------------------------------------------------------
  1529. ; EOL advances the cursor to the end of the command line.
  1530. ;------------------------------------------------------------------------------
  1531. eol        proc    near
  1532.         mov    cl,[si]            ;Get count
  1533.         cmp    cl,cs:[bufferptr]    ;Already at end?
  1534.         jb    eol_exit        ;Yes, then exit
  1535.         sub    cl,cs:[bufferptr]    ;Calculate distance from end
  1536.         inc    cl
  1537.         xor    ch,ch            ;Byte to word in CX
  1538. eol1:
  1539.         push    cx            ;Advance right CX times
  1540.         call    move_right
  1541.         pop    cx
  1542.         loop    eol1
  1543. eol_exit:
  1544.         ret
  1545. eol        endp
  1546. ;------------------------------------------------------------------------------
  1547. ; CLEAR_LINE clears the command line.
  1548. ; Entry: DS:SI - Ptr to current line buffer
  1549. ;           BH - current video page
  1550. ;------------------------------------------------------------------------------
  1551. clear_line    proc    near
  1552.         mov    cl,[si]            ;Get count
  1553.         xor    ch,ch
  1554.         jcxz    cline2            ;Exit if no characters
  1555.         push    cx            ;Save count
  1556.         call    home            ;Home the cursor
  1557.         mov    ah,3            ;Get cursor position
  1558.         int    10h
  1559.         pop    cx            ;Restore CX
  1560.         mov    al,32            ;Print ASCII spaces
  1561. cline1:
  1562.         call    print_char
  1563.         loop    cline1
  1564.         mov    ah,2            ;Home cursor again
  1565.         int    10h
  1566.         mov    byte ptr [si],0        ;Reset count
  1567. cline2:
  1568.         ret
  1569. clear_line    endp
  1570. ;----------------------------------------------------------------------------
  1571. ; CMP CMDLINES - Compare the current cmd to one in stack
  1572. ; Entry:  ES:DI - Stacked command
  1573. ; Exit:      ZF - Set if compare passed
  1574. ;----------------------------------------------------------------------------
  1575. cmp_cmdlines    proc    near
  1576.         push    di
  1577.         push    si
  1578.         push    ds
  1579.         lds    si,dword ptr cmdstack_headl ;Get ptr to cmp string
  1580.         xor    cx,cx
  1581.         lodsb
  1582.         or    cl,al            ;Get length of string
  1583.         jz    cmp_cmdlines_2
  1584.         inc    di
  1585.         call    chk_buffend
  1586.         call    chk_buffendsi
  1587. cmd_cmdlines_1:
  1588.         cmp    cs:chk_case,0        ;Flag determines if case
  1589.         jz    cmd_cmdlines_11        ;  respected.
  1590.         cmpsb    
  1591.         jmp    short cmd_cmdlines_12
  1592. cmd_cmdlines_11:
  1593.         lodsb                ;Ignore case check
  1594.         mov    ah,es:[di]
  1595.         inc    di
  1596.         or    ax,2020h
  1597.         cmp    al,ah
  1598. cmd_cmdlines_12:
  1599.         pushf
  1600.         call    chk_buffend
  1601.         call    chk_buffendsi
  1602.         popf
  1603.         jne    cmp_cmdlines_2
  1604.         loop    cmd_cmdlines_1
  1605.         mov    al,es:[di]
  1606. cmp_cmdlines_2:
  1607.         pop    ds
  1608.         pop    si
  1609.         pop    di
  1610.         ret
  1611. cmp_cmdlines    endp
  1612. ;----------------------------------------------------------------------------
  1613. ; SRCH_STACK searchs the command stack for a matching command.
  1614. ; Exit:    CF - clear if match found
  1615. ;       ES:DI - points to matching entry
  1616. ;----------------------------------------------------------------------------
  1617. srch_stack    proc    near
  1618.         assume    cs:code,ds:nothing
  1619.         push    di
  1620.         mov    es,cs:[cmdstack_seg]    ;Get ptr to head of stack
  1621.         mov    di,cs:[cmdstack_curr]
  1622. srch_stack_1:
  1623.         call    get_prev        ;Get ptr to prev command
  1624.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  1625.         je    srch_stack_exit        ;Yes, exit
  1626.         call    cmp_cmdlines        ;No, see if cmd matches
  1627.         jne    srch_stack_1        ;No match, keep looking
  1628.         or    al,al            ;See if full command checked
  1629.         jne    srch_stack_1
  1630.         clc
  1631.         pop    cx            ;Clear DI val on stack
  1632.         ret
  1633. srch_stack_exit:
  1634.         stc
  1635.         pop    di            ;Restore original DI
  1636.         ret
  1637. srch_stack    endp
  1638. ;----------------------------------------------------------------------------
  1639. ; DEL_CMD Deletes an entry in the command stack list
  1640. ; Entry: ES:DI - Ptr to entry to delete
  1641. ; Exit:  ES:DI - Ptr to last command in stack
  1642. ;----------------------------------------------------------------------------
  1643. del_cmd    proc    near
  1644.         assume    cs:code,ds:nothing
  1645.         push    si
  1646.         push    ds
  1647.         push    es
  1648.         pop    ds
  1649.         mov    si,di
  1650.         call    get_next        ;Get ptr to next command
  1651.         xchg    si,di
  1652. del_cmd_1:
  1653.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  1654.         je    del_cmd_3        ;Yes, exit
  1655.         mov    cl,ds:[si]        ;Get length of cmd
  1656.         xor    ch,ch
  1657.         inc    cx            ;Add 1 for count byte
  1658.         inc    cx            ;Add 1 for zero byte
  1659. del_cmd_2:
  1660.         movsb                ;Move next cmd over 
  1661.         call    chk_buffend        ;  current command.
  1662.         call    chk_buffendsi
  1663.         loop    del_cmd_2
  1664.         jmp    short del_cmd_1
  1665. del_cmd_3:
  1666.         mov    cx,si            ;Erase tail of last command.
  1667.         sub    cx,di            
  1668.         xor    al,al
  1669.         push    di
  1670. del_cmd_4:
  1671.         stosb
  1672.         loop    del_cmd_4
  1673.         pop    di
  1674. del_cmd_exit:
  1675.         pop    ds
  1676.         pop    si
  1677.         ret
  1678. del_cmd    endp
  1679. ;----------------------------------------------------------------------------
  1680. ; GET_PREV returns a pointer to the prev command in the stack.
  1681. ; Entry: ES:DI - Ptr to current command
  1682. ; Exit:  ES:DI - Ptr to prev command
  1683. ;----------------------------------------------------------------------------
  1684. get_prev    proc    near
  1685.         assume    cs:code,ds:nothing
  1686.         xor    al,al            ;Zero AL
  1687. get_prev_1:
  1688.         dec    di            ;Skip past preceeding zero
  1689.         call    chk_buffbase
  1690.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  1691.         je    get_prev_3
  1692.         cmp    es:[di],al        ;If zero, keep scanning back
  1693.         jz    get_prev_1        ;  past erased command.
  1694. get_prev_2:
  1695.         dec    di            ;Scan back to prev cmd
  1696.         call    chk_buffbase
  1697.         cmp    es:[di],al        ;Chk for zero byte
  1698.         jnz    get_prev_2
  1699.         inc    di            ;Scan forward to cmd
  1700.         call    chk_buffend
  1701. get_prev_3:
  1702.         ret
  1703. get_prev    endp
  1704. ;----------------------------------------------------------------------------
  1705. ; GET_NEXT returns a pointer to the next command in the stack.
  1706. ; Entry: ES:DI - Ptr to current command
  1707. ; Exit:  ES:DI - Ptr to next command
  1708. ;----------------------------------------------------------------------------
  1709. get_next    proc    near
  1710.         assume    cs:code,ds:nothing
  1711.         xor    ax,ax            ;Zero AL
  1712.         mov    al,es:[di]        ;Get cmd length
  1713.         add    di,ax
  1714.         inc    di            ;Inc for cnt byte.
  1715.         call    chk_buffend
  1716. get_next_1:
  1717.         mov    al,es:[di]        ;Get next char
  1718.         cmp    al,ah            ;Ah == 0
  1719.         jne    get_next_2
  1720.         cmp    di,cs:[cmdstack_head]    ;See if at end of list
  1721.         je    get_next_2
  1722.         inc    di
  1723.         call    chk_buffend
  1724.         jmp    short get_next_1
  1725. get_next_2:
  1726.         ret
  1727. get_next    endp
  1728. ;------------------------------------------------------------------------------
  1729. ; CMD_RECORD records the latest command in the command stack.
  1730. ; Entry:  DS:SI - input buffer address
  1731. ;            CX - length of cmd to save
  1732. ; Exit:   ES:DI - Points to end of cmd stored
  1733. ;------------------------------------------------------------------------------
  1734. cmd_record    proc    near
  1735.         assume    cs:code,ds:nothing
  1736.         inc    cx            ;Add 1 for zero byte
  1737.         les    di,dword ptr cmdstack_headl    ;Get head ptr 
  1738. cmd_record_1:
  1739.         movsb                ;Store character
  1740.         call    chk_buffend        ;Inc cmd buff ptr
  1741.         loop    cmd_record_1        ;Loop till done
  1742.         xor    ax,ax
  1743.         stosb                ;Store end of cmd byte
  1744.         push    di
  1745. cmd_record_2:
  1746.         call    chk_buffend        ;Inc cmd buff ptr
  1747.         cmp    byte ptr es:[di],0    ;Continue until end of
  1748.         je    cmd_record_3        ;  next command
  1749.         stosb                ;Store end of cmd byte
  1750.         jmp    short cmd_record_2
  1751. cmd_record_3:
  1752.         pop    di
  1753. cmd_record_exit:
  1754.         ret
  1755. cmd_record    endp
  1756. ;------------------------------------------------------------------------------
  1757. ; CHK_BUFFEND Checks the cmd buff ptr to see if it is valid
  1758. ; Entry:  ES:DI - Ptr to cmdstack buffer
  1759. ; Exit:   ES:DI - Updated
  1760. ;------------------------------------------------------------------------------
  1761. chk_buffend     proc    near
  1762.         assume    cs:code,ds:nothing
  1763.         cmp    di,cs:[cmdstack_end]    ;See if at end of buff
  1764.         jae    chk_buffend_1        ;Yes, reset ptr to base
  1765.         ret
  1766. chk_buffend_1:
  1767.         sub    di,cs:[cmdstack_size]    
  1768.         ret
  1769. chk_buffend     endp
  1770. ;------------------------------------------------------------------------------
  1771. ; CHK_BUFFENDSI Checks the cmd buff ptr to see if it is valid
  1772. ; Entry:  SI - Ptr to cmdstack buffer
  1773. ; Exit:   SI - Updated
  1774. ;------------------------------------------------------------------------------
  1775. chk_buffendsi    proc    near
  1776.         assume    cs:code,ds:nothing
  1777.         xchg    si,di
  1778.         call    chk_buffend
  1779.         xchg    si,di
  1780.         ret
  1781. chk_buffendsi     endp
  1782. ;------------------------------------------------------------------------------
  1783. ; CHK_BUFFBASE Checks the cmd buff ptr to see if it is valid
  1784. ; Entry:  ES:DI - Ptr to cmdstack buffer
  1785. ; Exit:   ES:DI - Updated
  1786. ;------------------------------------------------------------------------------
  1787. chk_buffbase     proc    near
  1788.         assume    cs:code,ds:nothing
  1789.         cmp    di,cs:[cmdstack_base]    ;See if at start of buff
  1790.         jbe    chk_buffbase_1        ;Yes, reset ptr to base
  1791.         ret
  1792. chk_buffbase_1:
  1793.         add    di,cs:[cmdstack_size]
  1794.         ret
  1795. chk_buffbase     endp
  1796. ;----------------------------------------------------------------------------
  1797. ; WRITE_CMD1 outputs a command string
  1798. ; Entry:  ES:DI - string offset address
  1799. ;         DS:SI - current line buffer
  1800. ; Exit:   AL - character after string
  1801. ;----------------------------------------------------------------------------
  1802. write_command    proc    near
  1803.         assume    cs:code,ds:nothing
  1804.         push    di            ;Save address
  1805.         call    clear_line        ;Clear input line
  1806.         pop    di            ;Retrieve string address
  1807.  
  1808.         push    ds            ;Save Ptr to line buffer
  1809.         push    si
  1810.  
  1811.         push    es            ;Swap pointers
  1812.         push    ds
  1813.         pop    es
  1814.         pop    ds
  1815.         xchg    si,di
  1816.  
  1817.         xor    cx,cx
  1818.         add    cl,[si]            ;Get string length
  1819.         movsb                ;Store string length
  1820.         jcxz    write2
  1821. write1:
  1822.         lodsb
  1823.         call    chk_buffendsi
  1824.         call    print_char
  1825.         stosb                ;Transfer character to buffer
  1826.         inc    cs:[bufferptr]        ;Advance pointer
  1827.         loop    write1            ;Loop until done
  1828. write2:
  1829.         pop    si            ;Restore line buff pointer
  1830.         pop    ds
  1831.         ret
  1832. write_command    endp
  1833. ;------------------------------------------------------------------------------
  1834. ; NEW_LINE prints a carrage return and linefeed to the screen
  1835. ;------------------------------------------------------------------------------
  1836. new_line    proc    near
  1837.         mov    al,13
  1838.         call    print_char
  1839.         mov    al,10
  1840.         call    print_char
  1841.         ret
  1842. new_line    endp
  1843. ;------------------------------------------------------------------------------
  1844. ; PRINT_STRING writes an ASCII string to the command line.
  1845. ; Entry:  DS:SI - string address
  1846. ;            CX - number of characters
  1847. ;------------------------------------------------------------------------------
  1848. print_string    proc    near
  1849.         jcxz    ps_exit            ;Exit if no characters
  1850. ps1:
  1851.         lodsb                ;Get a byte
  1852.         call    print_char        ;Print a byte
  1853.         loop    ps1            ;Loop until done
  1854. ps_exit:
  1855.         ret
  1856. print_string    endp
  1857. ;------------------------------------------------------------------------------
  1858. ; PRINT_CHAR writes an ASCII character to the screen
  1859. ; Entry:  AL - character
  1860. ;------------------------------------------------------------------------------
  1861. print_char    proc    near
  1862.         push    dx
  1863.         mov    ah,2            ;Print the character
  1864.         mov    dl,al            ;Transfer it to DL
  1865.         int    21h            ;Output character
  1866.         pop    dx
  1867.         ret
  1868. print_char    endp
  1869. ;------------------------------------------------------------------------------
  1870. ; SET_CURSOR sets the cursor mode based on the state of the insert flag.
  1871. ;------------------------------------------------------------------------------
  1872. set_cursor    proc    near
  1873.         mov    cx,cs:[points]        ;Get scan lines/char
  1874.         mov    ah,cs:[insert_flag]    ;Test state of insert flag
  1875.         xor    ah,cs:[insert_cursor]
  1876.         je    setc1            ;Branch if not set
  1877.         xor    ch,ch
  1878.         jmp    short setc2
  1879. setc1:
  1880.         mov    ch,cl
  1881.         dec    ch
  1882. setc2:
  1883.         mov    ah,1            ;Set cursor mode
  1884.         int    10h
  1885.         ret
  1886. set_cursor    endp
  1887. ;-----------------------------------------------------------------------------
  1888. ; HEX2ASC converts a binary number to ASCII and prints it to the screen.
  1889. ; Entry:  AX - binary number
  1890. ;-----------------------------------------------------------------------------
  1891. hex2asc        proc near
  1892.         assume    ds:nothing,es:nothing
  1893.         push    bx
  1894.         push    cx
  1895.         mov    cx,5            ;Allow max of five digits
  1896. hex_loop1:
  1897.         xor    dx,dx                   ;Clear high word
  1898.         mov    bx,10            ;Load number base
  1899.         div    bx            ;Divide by base (10)
  1900.         add    dl,30h              ;Convert to ascii
  1901.         push    dx                      ;Save digit on stack
  1902.         loop    hex_loop1
  1903.         mov    cx,5            ;Allow max of five digits
  1904.         mov    bl,"0"            ;Set leading zero indicator
  1905. hex_loop2:
  1906.         pop    ax            ;Get digit off stack
  1907.         or     bl,al             ;Don't print leading zeros.
  1908.         cmp    bl,"0"            ;The first non zero will
  1909.         je    hex_1            ;  change bl to non-zero.
  1910.         call    print_char
  1911. hex_1:
  1912.         loop    hex_loop2
  1913. hex_exit:
  1914.         pop    cx
  1915.         pop    bx
  1916.          ret
  1917. hex2asc         endp
  1918. ;-----------------------------------------------------------------------------
  1919. ; DELALIASENTRY - Deletes an alias entry
  1920. ; Entry:  ES:DI - pointer to the entry in the alias list to delete
  1921. ; Exit:      CF - clear if successful
  1922. ;-----------------------------------------------------------------------------
  1923. delete_aliasent    proc    near
  1924.         push    cx            ;Save registers
  1925.         push    si
  1926.         push    ds                      ;Yes, remove entry from list
  1927.  
  1928.         push    es                      ;  by moving the remainder of
  1929.         pop     ds                      ;  the list over this entry.
  1930.         mov    si,ds:[di]         ;Point SI to the next list
  1931.         add    si,di            ;  entry.
  1932. delent_1:
  1933.         cmp     word ptr ds:[si],-1       ;Check for the end of the list
  1934.         je    delent_2
  1935.         mov    cx,ds:[si]        ;Get size of entry
  1936.         rep    movsb            ;Copy next entry over current
  1937.         jmp    short delent_1        ;  entry.
  1938. delent_2:
  1939.         mov    word ptr es:[di],-1    ;Set end of list indicator
  1940.         pop    ds            ;Get back file buffer pointer
  1941.         pop    si
  1942.         pop    cx
  1943.         ret
  1944. delete_aliasent    endp
  1945. ;============================================================================
  1946. ; MUXINT processes calls to interrupt 2Fh
  1947. ; Entry:  AH - Device ID
  1948. ; Exit:   AL - 0FFh if AH = Alias device ID. Unchanged otherwise.
  1949. ;         ES - Code segment if AH = Alias device ID. Unchanged otherwise.
  1950. ;============================================================================
  1951. muxint        proc    far
  1952.             assume  cs:code,ds:nothing,es:nothing
  1953.         cmp    ax,1605h        ;See if Windows launch
  1954.         je    mux_winstart
  1955.         cmp    ax,1606h        ;See if Windows terminate
  1956.         je    mux_winend
  1957.  
  1958.         cmp     ax,4b05h                ;See if switcher get instance
  1959.             je      init_instance           ;  data.
  1960.  
  1961.         cmp    ah,cs:[multiplex_id]    ;Check for program ID
  1962.         je    muxint_1        ;Its us, indicate installed.
  1963. muxint_jmp:
  1964.             jmp     cs:[int2Fh]             ;Jump to old int
  1965. mux_winend:
  1966.             test    dl,01h                  ;See if enhanced mode Windows
  1967.             jne     muxint_jmp
  1968.         dec    cs:win_enhanced        ;Clear Enhanced mode win flag
  1969.             jmp     short muxint_jmp
  1970. mux_winstart:
  1971.             test    dl,01h                  ;See if enhanced mode Windows
  1972.             jne     init_instance
  1973.             inc     cs:win_enhanced
  1974. init_instance:
  1975.             pushf
  1976.             call    cs:[int2fh]             ;Call old int
  1977.             mov     word ptr cs:[sisNextDev],bx
  1978.             mov     word ptr cs:[sisNextDev+2],es
  1979.             push    cs                      ;ES:BX point to switcher struc
  1980.             pop     es
  1981.             mov     bx,offset StartupInfo
  1982.             iret
  1983. muxint_1:
  1984.         mov    al,-1            ;Indicate Alias installed
  1985.         push    cs            ;ES = installed code segment
  1986.         pop    es
  1987.         iret
  1988. muxint        endp
  1989.  
  1990.         even                ;Align stack on word boundry
  1991. end_of_resident    =    $
  1992.  
  1993. ;----------------------------------------------------------------------------
  1994. ; Start of non-resident code.
  1995. ;----------------------------------------------------------------------------
  1996. final_install:
  1997.         rep    movsb            ;Copy alias list
  1998.         cld                ;Correct DF if necessary
  1999.         mov    di,aliaslist_size    ;Init key assignment lists
  2000.         mov    si,keylist_base
  2001.         mov    cx,MAXKEYS
  2002.         mov    keylist_base,di        ;Copy key lists to area
  2003.         push    cx            ;  just past alias buffer
  2004.         rep    movsw
  2005.         pop    cx
  2006.         mov    cmdlist_base,di
  2007.         rep    movsw
  2008.  
  2009.         xor    al,al
  2010.         mov    di,cmdstack_base    ;Initialize command stack
  2011.         mov    cx,cmdstack_size    ;  area with zeros
  2012.         jcxz    tsr            ;Branch if size is zero
  2013.         rep    stosb
  2014. tsr:
  2015.         mov    ax,3100h        ;Terminate and stay resident
  2016.         int    21h
  2017. ;----------------------------------------------------------------------------
  2018. ; Non-resident data.
  2019. ;----------------------------------------------------------------------------
  2020. alrdy_installed    db    0            ;Installed flag
  2021. other_seg    dw    0            ;Segment of installed code
  2022. databuff_seg    dw    0            ;Segment of data buffer.
  2023.  
  2024. alias_buffer    dw    512            ;Extra buffer for alias list.
  2025. aliaslist_end    dw    0            ;Offset of end of the list.
  2026. alias_inlist    db    0            ;Flag used in alias list append
  2027.  
  2028. infomsg1    db    "PCMKEY uninstalled",0
  2029. infomsg2    db    13,10,9,"Command stack size: ",0
  2030. infomsg3    db    13,10,9,"Minimum stacked command length: ",0
  2031. infomsg4    db    13,10,9,"Bytes free in alias buffer: ",0
  2032. infomsg5    db    13,10,9,"Alias translation is ",0
  2033. infomsg5d    db    "disabled",13,10,0
  2034. infomsg5e    db    "enabled",13,10,0
  2035. infomsg6    db    13,10,"//",9,"KEY ASSIGNMENTS",0
  2036. infomsg7    db    13,10,"//",9,"ALIAS DEFINITIONS",0
  2037. infomsg8    db    13,10,"For help type PCMKEY ?",0
  2038.  
  2039. filemsg1    db    13,10,"Error in line ",0    ;File identification message.
  2040. filemsg2    db    " of file: "
  2041. filenam_field    db    78 dup (0)        ;Name of current entry file.
  2042.  
  2043. errmsg0        db    "Need DOS 3.1 or greater",0
  2044. errmsg1        db    "PCMKEY not installed",0
  2045.  
  2046. errmsg2        db    13,10,"Syntax: PCMKEY [alias [command]]"
  2047.         db    "[/B n][/C][/D][/E][/F filename]",13,10
  2048.         db    14 dup (" ")
  2049.         db    "[/I+|-][/K][/L][/M n][/Pc][/S n][/U]",13,10,10
  2050.         db         9,"PCMKEY alias command",13,10
  2051.         db         9,"PCMKEY [key] [function] or command",13,10,10
  2052.         db         9,"/B = Set buffer size*",13,10
  2053.         db         9,"/C = Toggle underline cursor for insert",13,10
  2054.         db         9,"/D = Disable alias translation",13,10
  2055.         db         9,"/E = Enable alias translation",13,10
  2056.         db         9,"/F = Define filename of command file",13,10
  2057.         db         9,"/I = Change ignore/match case in search",13,10
  2058.         db         9,"/K = List key assignments",13,10
  2059.         db         9,"/L = List aliases",13,10
  2060.         db         9,"/M = Minimum command length to stack",13,10
  2061.         db         9,"/P = Define command separator*",13,10
  2062.         db         9,"/S = Set size of command stack*",13,10
  2063.         db         9,"/U = Uninstall",13,10,10
  2064.         db         9,"* switches valid only at install time.",13,10
  2065.         db    0
  2066.  
  2067. errmsg3        db    "Can",39,"t uninstall",0
  2068. errmsg4        db    "Can",39,"t change parameter after installation",0
  2069. errmsg5        db    "Illegal number",0
  2070. errmsg6        db    "Can",39,"t find alias file",0
  2071. errmsg8        db    "Not enough memory",0
  2072. errmsg9        db    "Alias list full",0
  2073. errmsg10    db    "DOSKEY installed",0
  2074. errmsg11    db    "Invalid key assignment",0
  2075. errmsg12    db    "Number too big",0
  2076. errmsg13    db    "Alias not in list",0
  2077. errmsg14    db    "Error using Int 2Fh",0
  2078. errmsg15    db    "+ or - must follow /I",0
  2079. errmsg16    db    "Unsupported key combination",0
  2080. errmsg17    db    "Unknown editor command",0
  2081. errmsg18    db    "Bad $ switch",0
  2082. errmsg19    db    "Too many key assignments",0
  2083.  
  2084. filebuf_size    dw    0400h            ;Size of input file buffer.
  2085. max_list_size    dw    1000h            ;Max size of installed code.
  2086.  
  2087. file_linecount    dw    0            ;Line number being processed.
  2088. caps_flag    db    0
  2089. param_found    db    0            ;Cmd line parameter found flag
  2090. append_cr    db    0            ;Append cr to alias flag
  2091.  
  2092. cmd_switches    db    "sfeldbumipkc*/"    ;Letters of valid commands.
  2093. cmd_switch_end    =    $
  2094. cmd_jmp_tbl    dw    offset setstacksize    ;This jump table is used to
  2095.         dw    offset loadaliasfile    ;  call the routines that
  2096.         dw    offset enablealias      ;  process the command line
  2097.         dw    offset listalias1    ;  arguments
  2098.         dw    offset disablealias
  2099.         dw    offset setlistbuffer
  2100.         dw    offset remove
  2101.         dw    offset minstacklen
  2102.         dw    offset checkcase
  2103.         dw    offset cmdsepchar
  2104.         dw    offset listkeys
  2105.         dw    offset inscursor
  2106.         dw    offset comment_line    ;Comments can be indicated by
  2107.         dw    offset comment_line    ;  a /* or a //.
  2108.  
  2109. keys        dw    8047h,8048h,803dh,804bh,804dh
  2110.         dw    804fh,8050h,8052h,8053h,8473h
  2111.         dw    8474h,8475h,0008h,0009h,001bh
  2112.         dw    047fh,000dh,8041h,8043h,886eh
  2113.         dw    8871h,0403h,0407h,0408h,040dh
  2114. keys_end    =    $
  2115.  
  2116. keylist_entry    dw    offset home        ;Jump table for standard
  2117.         dw    offset prev_cmd        ;  keys.  Groups of 5 match
  2118.         dw    offset prev1_cmd    ;  keys table above.
  2119.         dw    offset move_left
  2120.         dw    offset move_right
  2121.  
  2122.         dw    offset eol
  2123.         dw    offset next_cmd
  2124.         dw    offset toggle_ins
  2125.         dw    offset delete
  2126.         dw    offset ctrl_left
  2127.  
  2128.         dw    offset ctrl_right
  2129.         dw    offset ctrl_end
  2130.         dw    offset backspace
  2131.         dw    offset tab
  2132.         dw    offset clr_cmd
  2133.  
  2134.         dw    offset ctrl_bs
  2135.         dw    offset enter        
  2136.         dw    offset dump_stack
  2137.         dw    offset pick_stack
  2138.         dw    offset clr_stack
  2139.  
  2140.         dw    offset clr_aliases
  2141.         dw    offset abort_cmd
  2142.         dw    offset beep_cmd
  2143.         dw    offset backspace    ;Cmds duped in ctl chars
  2144.         dw    offset enter        ;  for default action
  2145.  
  2146.         dw    offset shift1_key    ;Cmds not preassigned
  2147.         dw    offset shift2_key
  2148.         dw    offset shift3_key
  2149.         dw    offset nop_cmd
  2150. keylist_e_end    =     $
  2151.  
  2152. keycmds        db    "home",0
  2153.                db    "srchcmd",0
  2154.                db    "prevcmd",0
  2155.                db    "charleft",0
  2156.                db    "charright",0
  2157.  
  2158.         db    "end",0
  2159.                db    "nextcmd",0
  2160.                db    "toggleins",0
  2161.                db    "del",0
  2162.                db    "wordleft",0
  2163.  
  2164.                db    "wordright",0
  2165.                db    "del2eol",0
  2166.                db    "bksp",0
  2167.                db    "tab",0
  2168.                db    "clrcmd",0
  2169.  
  2170.         db    "wordbksp",0
  2171.                db    "enter",0
  2172.                db    "dumpstack",0
  2173.                db    "pickcmd",0
  2174.                db    "clrstack",0
  2175.  
  2176.         db    "clraliases",0
  2177.         db    "abortcmd",0
  2178.         db    "beep",0
  2179.         db    1,0            ;Fake labels allow dual use
  2180.         db    1,0            ;  of keylist for default
  2181.                         ;  key assignments.
  2182.                db    "prefix1",0
  2183.                db    "prefix2",0
  2184.                db    "prefix3",0
  2185.                db    "nop",0,0
  2186.  
  2187.         align    16
  2188. keycodes    dw    0027h,0322h,0    ,0      ; '
  2189.         dw    002ch,033ch,0    ,0      ; ,
  2190.         dw    002dh,035fh,0    ,8882h  ; -
  2191.         dw    002eh,033eh,0    ,0      ; .
  2192.         dw    002fh,033fh,0    ,0      ; /
  2193.         dw    0030h,0329h,0    ,8881h  ; 0
  2194.         dw    0031h,0321h,0    ,8878h  ; 1
  2195.         dw    0032h,0340h,0    ,8879h  ; 2
  2196.         dw    0033h,0323h,0    ,8880h  ; 3
  2197.         dw    0034h,0324h,0    ,8881h  ; 4
  2198.         dw    0035h,0325h,0    ,8882h  ; 5
  2199.         dw    0036h,035eh,0    ,8883h  ; 6
  2200.         dw    0037h,0326h,0    ,8884h  ; 7
  2201.         dw    0038h,032ah,0    ,8885h  ; 8
  2202.         dw    0039h,0328h,0    ,8886h  ; 9
  2203.         dw    003bh,033ah,0    ,0      ; ;
  2204.         dw    003dh,032bh,0    ,8883h  ; =
  2205.         dw    005bh,037bh,041bh,0      ; [
  2206.         dw    005ch,037ch,041ch,0      ; \
  2207.         dw    005dh,037dh,041dh,0      ; ]
  2208.         dw    0060h,037eh,0    ,0      ; `
  2209.  
  2210.         dw    0061h,0341h,0401h,881eh  ; a
  2211.         dw    0062h,0342h,0402h,8830h  ; b
  2212.         dw    0063h,0343h,0403h,882eh  ; c
  2213.         dw    0064h,0344h,0404h,8820h  ; d
  2214.         dw    0065h,0345h,0405h,8812h  ; e
  2215.         dw    0066h,0346h,0406h,8821h  ; f
  2216.         dw    0067h,0347h,0407h,8822h  ; g
  2217.         dw    0068h,0348h,0408h,8823h  ; h
  2218.         dw    0069h,0349h,0409h,8817h  ; i
  2219.         dw    006ah,034ah,040ah,8824h  ; j
  2220.         dw    006bh,034bh,040bh,8825h  ; k
  2221.         dw    006ch,034ch,040ch,8826h  ; l
  2222.         dw    006dh,034dh,040dh,8832h  ; m
  2223.         dw    006eh,034eh,040eh,8831h  ; n
  2224.         dw    006fh,034fh,040fh,8818h  ; o
  2225.         dw    0070h,0350h,0410h,8819h  ; p
  2226.         dw    0071h,0351h,0411h,8810h  ; q
  2227.         dw    0072h,0352h,0412h,8813h  ; r
  2228.         dw    0073h,0353h,0413h,881fh  ; s
  2229.         dw    0074h,0354h,0414h,8814h  ; t
  2230.         dw    0075h,0355h,0415h,8816h  ; u
  2231.         dw    0076h,0356h,0416h,882fh  ; v
  2232.         dw    0077h,0357h,0417h,8811h  ; w
  2233.         dw    0078h,0358h,0418h,882dh  ; x
  2234.         dw    0079h,0359h,0419h,8815h  ; y
  2235.         dw    007ah,035ah,041ah,882ch  ; z
  2236. single_key_end    =    $
  2237.         dw    8047h,8347h,8477h,8897h  ; home  
  2238.         dw    8048h,8348h,0    ,8898h  ; up    
  2239.         dw    8049h,8349h,8484h,8899h  ; pgup  
  2240.         dw    804bh,834bh,8473h,889bh  ; left  
  2241.         dw    804dh,834dh,8474h,889dh  ; right 
  2242.         dw    804fh,834fh,8475h,889fh  ; end   
  2243.         dw    8050h,8350h,8450h,88a0h  ; down  
  2244.         dw    8051h,8351h,8476h,88a1h  ; pgdn  
  2245.         dw    8052h,8352h,0    ,88a2h  ; ins   
  2246.         dw    8053h,8353h,0    ,88a3h  ; del   
  2247.         dw    0008h,0308h,047fh,0      ; bksp  
  2248.         dw    0009h,830fh,0    ,0      ; tab   
  2249.         dw    000dh,030dh,040ah,0      ; enter 
  2250.         dw    001bh,031bh,041bh,0      ; esc   
  2251.         dw    0020h,0    ,0    ,8020h  ; space 
  2252.         dw    803bh,8354h,845eh,8868h  ; F1
  2253.         dw    803ch,8355h,845fh,8869h  ; F2
  2254.         dw    803dh,8356h,8460h,886ah  ; F3
  2255.         dw    803eh,8357h,8461h,886bh  ; F4
  2256.         dw    803fh,8358h,8462h,886ch  ; F5
  2257.         dw    8040h,8359h,8463h,886dh  ; F6
  2258.         dw    8041h,835ah,8464h,886eh  ; F7
  2259.         dw    8042h,835bh,8465h,886fh  ; F8
  2260.         dw    8043h,835ch,8466h,8870h  ; F9
  2261.         dw    8044h,835dh,8467h,8871h  ; F10
  2262. keycodes_end    =    $
  2263.  
  2264. keynames    db    "home",0
  2265.         db    "up",0
  2266.         db    "pgup",0
  2267.         db    "left",0
  2268.         db    "right",0
  2269.         db    "end",0
  2270.         db    "down",0
  2271.         db    "pgdn",0
  2272.         db    "ins",0
  2273.         db    "del",0
  2274.         db    "bksp",0
  2275.         db    "tab",0
  2276.         db    "enter",0
  2277.         db    "esc",0
  2278.         db    "space",0
  2279.         db    "f1",0
  2280.         db    "f2",0
  2281.         db    "f3",0
  2282.         db    "f4",0
  2283.         db    "f5",0
  2284.         db    "f6",0
  2285.         db    "f7",0
  2286.         db    "f8",0
  2287.         db    "f9",0
  2288.         db    "f10",0,0
  2289. keynames_end    =    $
  2290.  
  2291. keyletters    db    "',-./0123456789;=[\]`"
  2292.         db    "abcdefghijklmnopqrstuvwxyz"
  2293. keyletters_end    =    $
  2294. ;----------------------------------------------------------------------------
  2295. ; Initialization routine.
  2296. ;----------------------------------------------------------------------------
  2297. initialize    proc    near
  2298.         assume    cs:code,ds:code,es:code
  2299.         cld
  2300.         mov    ah,30h            ;Get DOS version
  2301.         int    21h
  2302.         xchg    al,ah            ;Swap major, minor numbers
  2303.         mov    dx,offset errmsg0    ;Bad DOS version
  2304.         cmp    ax,30ah            ;Run if DOS 3.1 or greater.
  2305.         jb     jmp_disp_error
  2306.         mov    dos_version,ax        ;Save version number
  2307.         
  2308.         mov    ax,4800h        ;Check for DOSKEY
  2309.         int    2fh
  2310.         mov    dx,offset errmsg10    ;DOSKEY installed
  2311.         or    al,al
  2312.         jne    jmp_disp_error
  2313.  
  2314.         mov    bx,offset end_of_code + STACKSIZE   ;Init ptrs
  2315.         mov    sp,bx
  2316.         mov    word ptr [aliaslist_ptr],bx
  2317.         mov    ax,cs
  2318.         mov    word ptr [aliaslist_ptr+2],ax
  2319.         mov    word ptr [bx],-1    ;Initialize alias list
  2320.         lea    cx,[bx+4]        ;  by writing a -1 as
  2321.         mov    aliaslist_end,cx
  2322.         add    bx,max_list_size
  2323.         mov    aliaslist_size,bx
  2324.  
  2325.         mov    di,bx            ;Init key assignment lists
  2326.         mov    si,offset keys
  2327.         mov    cx,offset keys_end - offset keys
  2328.         shr    cx,1
  2329.         mov    keys_cnt,cx
  2330.         push    cx
  2331.         rep    movsw
  2332.         pop    cx
  2333.         mov    keylist_base,bx        ;Init ptr to keylist
  2334.         add    bx,MAXKEYS * 2
  2335.         mov    di,bx
  2336.         mov    si,offset keylist_entry
  2337.         rep    movsw
  2338.         mov    cmdlist_base,bx
  2339.         add    bx,MAXKEYS * 2
  2340.  
  2341.         mov    cl,4
  2342.         shr    bx,cl
  2343.         mov    ah,4ah            ;Reduce memory allocation
  2344.          int    21h
  2345.  
  2346.         mov    bx,filebuf_size        ;Get size of file buffer,
  2347.          mov    ah,48h            ;Allocate memory block
  2348.          int    21h
  2349.          mov    dx,offset errmsg8    ;Not enough memory msg
  2350.          jc    jmp_disp_error
  2351.         mov    databuff_seg,ax        ;Save segment to file buffer.
  2352.  
  2353.         call    find_installed
  2354.         jnc    init1
  2355. jmp_disp_error:
  2356.         jmp    disp_error            ;  msg and exit.
  2357. ;
  2358. ;Copy the command line to the file buffer to treat as a one line file.
  2359. ;
  2360. init1:
  2361.         mov    ax,databuff_seg        ;Get segment of file buffer.
  2362.         mov    es,ax            ;Treat the command line as
  2363.         xor    di,di            ;  a 1 line file.
  2364.         mov    si,offset command_tail
  2365.         xor    cx,cx
  2366.         or    cl,[si]            ;Get command line length
  2367.         je    parse_line_end        ;If zero, skip parse routine
  2368.         inc    si                      ;Copy command line into file
  2369.         inc    cx            ;  buffer.
  2370.         push    cx
  2371.         rep    movsb
  2372.         pop    cx            ;CX = file size.
  2373.         xor    si,si            ;Point SI to start of buffer
  2374.         push    es
  2375.         pop    ds            ;Set DS to file buffer seg
  2376.         assume    ds:nothing,es:nothing
  2377.         mov    es,cs:[other_seg]     ;Set ES to installed code
  2378. ;
  2379. ;Parse command line and command files.
  2380. ;
  2381. parse_line_loop:
  2382.         xor    bl,bl
  2383.         call    scanline             ;Get 1st character
  2384.         jc    parse_2                 ;If carriage return, skip line
  2385.         cmp    al,"/"            ;Compare character to switch.
  2386.         je    parse_switch_found
  2387.         cmp    al,"?"            ;See if help character
  2388.         mov    dx,offset errmsg2    ;Command not found msg
  2389.         je    disp_error
  2390.         call    setkey              ;Must be alias definition
  2391.         jc    disp_error
  2392.         mov    param_found,1        ;Set parameter found flag
  2393.         jmp    short parse_2        ;Return to parse loop
  2394. parse_switch_found:
  2395.         mov    param_found,1        ;Set parameter found flag
  2396.         lodsb                ;Get command line switch
  2397.         dec    cx
  2398.         cmp    al,'A'             ;Convert to lower case if
  2399.         jb    parse_1            ;  necessary.
  2400.         cmp    al,'Z'
  2401.         ja    parse_1
  2402.         or    al,20h
  2403. parse_1:
  2404.         push    cx            ;Scan the list of allowable
  2405.         push    es            ;  command switches. If switch
  2406.         push    cs            ;  found, use its position for
  2407.         pop    es            ;  an index into the list of
  2408.         mov    di,offset cmd_switches    ;  routines.
  2409.         mov    cx,offset cmd_switch_end - offset cmd_switches
  2410.         mov    bx,offset cmd_switch_end - offset cmd_switches - 1
  2411.         repne    scasb
  2412.         mov    ax,cx            ;Copy index into list
  2413.         pop    es
  2414.         pop    cx
  2415.         mov    dx,offset errmsg2    ;Command not found msg
  2416.         jne    disp_error
  2417.         sub    bx,ax            ;Compute offset into list
  2418.         shl    bx,1            ;Convert to word offset
  2419.         call    cs:[bx+offset cmd_jmp_tbl] ;Call command routine.
  2420.         jc    disp_error        ;If error terminate parse.
  2421. parse_2:
  2422.         jcxz    parse_line_end        ;If at file end, exit parse.
  2423.                 jmp    short parse_line_loop
  2424. ;
  2425. ;See if installed. If not, install.
  2426. ;
  2427. parse_line_end:
  2428.         cmp    cs:[param_found],1    ;See if any parameters found
  2429.         je     init2            ;If already installed and
  2430.         cmp    cs:[alrdy_installed],0    ;  no parameters on the
  2431.         je    init2            ;  command line, default to
  2432.         mov    es,cs:[other_seg]     ;  showing program information
  2433.         call    listalias
  2434. init2:
  2435.         mov    ah,49h            ;Release memory block used
  2436.         mov    es,cs:[databuff_seg]    ;  for file buffer.
  2437.         int    21h
  2438.         push    cs
  2439.         pop    ds
  2440.         assume    ds:code
  2441.         mov    word ptr databuff_seg,0    ;Indicate file buff released
  2442.         cmp    alrdy_installed,0    ;If not already installed,
  2443.         je    install            ;  jump to install routine.
  2444. exit:
  2445.         mov    ax,4C00h        ;Terminate with RC = 0
  2446.         int    21h
  2447. ;
  2448. ;Display error message.
  2449. ;
  2450.         assume    ds:nothing
  2451. disp_error:
  2452.         xor    ax,ax            ;If file buffer still
  2453.         or     ax,cs:databuff_seg    ;  allocated, deallocate it.
  2454.         jz    disp_error0
  2455.         mov    ah,49h            ;Release memory block used
  2456.         mov     es,ax            ;  for file buffer.
  2457.         int    21h
  2458. disp_error0:
  2459.         push    cs
  2460.         pop    ds
  2461.         assume    ds:code
  2462.         cmp    byte ptr filenam_field,0
  2463.         je    disp_error1             ;If processing a file, print
  2464.         push    dx                      ;  a message informing the
  2465.         mov    dx,offset filemsg1      ;  user the filename being
  2466.         call    printmsg                ;  processed and the line
  2467.         mov    ax,file_linecount       ;  that the error occured.
  2468.         call    hex2asc
  2469.         mov    dx,offset filemsg2
  2470.         call    printmsgcr
  2471.         pop    dx
  2472. disp_error1:
  2473.         call    printmsgcr        ;print string
  2474.         mov    ax,4c01h        ;Terminate with RC = 1
  2475.         int    21h
  2476. ;
  2477. ;Install routine. Find segment of COMMAND.COM, hook into int 21h, 2Fh and TSR.
  2478. ;
  2479. install:
  2480.         mov    dx,offset program       ;Display copyright message
  2481.         call    printmsg
  2482. ;
  2483. ;Set up pointers to the cmd stack and to move the alias list to the end of the
  2484. ;command stack so it takes up less space when ALIAS resident.
  2485. ;
  2486.  
  2487.         mov    di,RES_STACK        ;Get base of internal stack
  2488.         mov    work_buff_ptr,di    ;Copy ptr to alias buffer
  2489.         add    di,128            ;Add size of buffer
  2490.         mov    cmdstack_base,di    ;Copy for start of cmd stack
  2491.         mov    cmdstack_head,di
  2492.         mov    cmdstack_curr,di
  2493.  
  2494.         mov    cmdstack_seg,ds        
  2495.         add    di,cmdstack_size
  2496.         mov    cmdstack_end,di
  2497.  
  2498.         mov    si,word ptr aliaslist_ptr    ;Save start of the
  2499.         mov    cx,aliaslist_end        ;  alias list.
  2500.         mov     word ptr aliaslist_ptr,di    ;Save new pointer.
  2501.         sub    cx,si               ;Compute size of list.
  2502.         mov    dx,di            ;See if we have enough room
  2503.         add    dx,cx            ;  for everything in one seg.
  2504.         add    dx,alias_buffer        ;Add additional space for list
  2505.         mov    aliaslist_size,dx    ;Save pointer to end of seg
  2506.         add    dx,MAXKEYS * 4        ;Add room for key lists
  2507.  
  2508.         mov    ax,offset command_tail
  2509.         mov    word ptr [temp_buff],ax
  2510.         mov    word ptr [temp_buff+2],cs
  2511. ;
  2512. ;Init switcher structures
  2513. ;
  2514.             mov     word ptr [TempBlockPtr+2],cs
  2515.             mov     word ptr [TempBlockPtr],ax
  2516.  
  2517.             mov     word ptr [DataBlockPtr+2],cs
  2518.             mov     word ptr [DataBlockPtr],offset DataBlock
  2519.             mov     word ptr [DataBlockSize],INSTDATASIZE
  2520.  
  2521.             mov     word ptr [StackBlockPtr+2],cs
  2522.             mov     word ptr [StackBlockPtr],offset end_of_resident
  2523.         mov    bx,dx
  2524.         sub    bx,offset end_of_resident    ;Compute size of
  2525.             mov     word ptr [StackBlockSize],bx    ;  Data save area
  2526.  
  2527.             mov     word ptr [sisInstData+2],cs
  2528.             mov     word ptr [sisInstData],offset DataBlockPtr
  2529.         
  2530.         push    dx
  2531.         mov     ax,1600h                ;See if Enhanced mode windows
  2532.             int     2fh
  2533.             or      al,al
  2534.             je      nowin
  2535.             inc     win_enhanced            ;Set enhanced mode flag
  2536. nowin:
  2537. ;
  2538. ;Revector interrupts 21h and 2Fh (if necessary).
  2539. ;
  2540.         mov    ax,3521h        ;Get interrupt 21 (DOS)
  2541.         int    21h                     ;  vector.
  2542.         mov    word ptr [int21h],bx
  2543.         mov    word ptr [int21h+2],es
  2544.         push    dx            ;Save memory size parameter
  2545.         mov    ax,2521h                ;Point int 21 to internal
  2546.         mov    dx,offset dosint        ;  routine.
  2547.         int    21h
  2548.  
  2549.         mov    ax,352fh        ;Get interrupt 2F (MUX)
  2550.         int    21h                     ;  vector.
  2551.         mov    word ptr [int2fh],bx
  2552.         mov    word ptr [int2fh+2],es
  2553.         mov    ax,252fh                ;Point int 2F to internal
  2554.         mov    dx,offset muxint        ;  routine.
  2555.         int    21h
  2556.  
  2557.         pop     dx            ;Get Ptr to end of resident
  2558.         add    dx,15            ;Convert memory needed to
  2559.         shr    dx,1            ;  paragraphs.
  2560.         shr    dx,1
  2561.         shr    dx,1
  2562.         shr    dx,1
  2563.         cmp    di,si            ;Check for overlap in the move
  2564.         jb    install_2        ;If overlap, copy list from
  2565.         std                ;  the top down to avoid
  2566.         add    di,cx            ;  overwriting the list.
  2567.         add    si,cx
  2568.         dec    si
  2569.         dec    di
  2570. install_2:
  2571.         push    ds            ;ES = DS
  2572.         pop    es
  2573.                 jmp    final_install        ;Jump to safe place for move.
  2574. initialize    endp
  2575.  
  2576. ;-----------------------------------------------------------------------------
  2577. ; CMPHEADER compares the first 16 bytes of this file with the segment
  2578. ;           pointed to by ES.
  2579. ; Entry:  DS - code segment
  2580. ;         ES - pointer to segment to compare
  2581. ; Exit:   ZF - 0 = segments match.
  2582. ;-----------------------------------------------------------------------------
  2583. cmpheader    proc    near
  2584.         mov    si,offset main+2    ;Search this segment for ASCII
  2585.         mov    di,si            ;  fingerprint.
  2586.         mov    cx,16
  2587.         repe    cmpsb
  2588.         ret
  2589. cmpheader    endp
  2590. ;-----------------------------------------------------------------------------
  2591. ; FIND INSTALLED Find the installed code by scanning the memory control blocks.
  2592. ; Exit:   AX - Segment of installed code if found.
  2593. ;         CF - Clear if installed code found
  2594. ;-----------------------------------------------------------------------------
  2595. find_installed  proc    near
  2596.             assume  ds:code,es:code
  2597.         mov    cx,16            ;Try 16 different IDs.
  2598. find_installed_1:
  2599.         xor    ax,ax
  2600.         mov    es,ax
  2601.         mov    ah,multiplex_id        ;Load ID.  Use Int 2Fh to
  2602.         int    2fh            ;  reach installed code so
  2603.         or    al,al            ;  that we are compatible
  2604.         jne    find_installed_2          ;  with 386 memory managers.
  2605.         push    cs
  2606.         pop    es                      ;If AL not changed, ALIAS not
  2607.         jmp    short find_installed_4    ;  installed.
  2608. find_installed_2:
  2609.         push    cx
  2610.         call    cmpheader        ;See if really Alias by
  2611.         pop    cx                      ;  comparing file headers.
  2612.         je    find_installed_3
  2613.         inc    multiplex_id        ;ID used by another program.
  2614.         loop    find_installed_1          ;  Change and try again.
  2615.         push    cs
  2616.         pop    es
  2617.         mov    dx,offset errmsg14    ;All IDs taken, print error
  2618.         jmp    find_installed_exit
  2619. find_installed_3:
  2620.         inc    alrdy_installed        ;Set installed flag
  2621. find_installed_4:
  2622.         clc
  2623. find_installed_exit:
  2624.         mov    other_seg,es        ;Save seg of installed code
  2625.         ret        
  2626. find_installed  endp
  2627.  
  2628. ;-----------------------------------------------------------------------------
  2629. ; PRINTMSG prints the message pointed to by DX to the screen.
  2630. ; Entry:  DX - pointer to ASCII message terminated by 0
  2631. ;-----------------------------------------------------------------------------
  2632. printmsg    proc    near
  2633.         assume    ds:nothing,es:nothing
  2634.         push    si
  2635.         push    ds
  2636.         push    cs
  2637.         pop    ds
  2638.         assume    ds:code
  2639.         mov    si,dx
  2640. printmsg1:
  2641.         lodsb
  2642.         or    al,al
  2643.         je    printmsg2
  2644.         call    print_char
  2645.         jmp    short printmsg1
  2646. printmsg2:
  2647.         pop    ds
  2648.         pop    si
  2649.         ret
  2650. printmsg    endp
  2651.  
  2652. ;-----------------------------------------------------------------------------
  2653. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  2654. ; Entry:  DX - pointer to ASCII message terminated by $
  2655. ;-----------------------------------------------------------------------------
  2656. printmsgcr    proc    near
  2657.         assume    ds:nothing,es:nothing
  2658.         push    dx
  2659.         call    printmsg
  2660.         mov    dx,offset endmsg
  2661.         call    printmsg
  2662.         pop    dx
  2663.         ret
  2664. printmsgcr    endp
  2665.  
  2666. ;-----------------------------------------------------------------------------
  2667. ; SETSTACKSIZE - Sets the size of the command line stack.
  2668. ; Entry:  DS:SI - points to stack size in ascii
  2669. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  2670. ;-----------------------------------------------------------------------------
  2671. setstacksize    proc    near
  2672.         assume    ds:nothing,es:nothing
  2673.         xor    bl,bl            ;Check for installed code
  2674.         call    setparameter        ;Get num and convert to binary
  2675.         jc    setstack_exit        ;Check for error
  2676.         mov    dx,20h
  2677.         mul    dx
  2678.         je    setstack_1
  2679.         cmp    ax,128
  2680.         ja    setstack_1        ;Stack must be at least 1
  2681.         mov    ax,128            ;  max cmd length in size.
  2682. setstack_1:
  2683.         mov    cs:[cmdstack_size],ax    ;Save parameter
  2684. setstack_exit:
  2685.         ret
  2686. setstacksize    endp
  2687.  
  2688. ;-----------------------------------------------------------------------------
  2689. ; SETLISTBUFFER - Sets the size of the additional buffer reserved for alias
  2690. ;                 list expansion.
  2691. ; Entry:  DS:SI - points to buffer size in ascii
  2692. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  2693. ;-----------------------------------------------------------------------------
  2694. setlistbuffer    proc    near
  2695.         assume    ds:nothing,es:nothing
  2696.         xor    bl,bl            ;Check for installed code
  2697.         call    setparameter        ;Get num and convert to binary
  2698.         jc    setlistbuffer_exit      ;Check for error
  2699.         mov    cs:[alias_buffer],ax    ;Save buffer size parameter
  2700. setlistbuffer_exit:
  2701.         ret
  2702. setlistbuffer    endp
  2703.  
  2704. ;-----------------------------------------------------------------------------
  2705. ; MINSTACKLEN - sets the minimum length of a command to stack.
  2706. ; Entry:     ES - segment of the installed code
  2707. ;         DS:SI - points to buffer size in ascii
  2708. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  2709. ;-----------------------------------------------------------------------------
  2710. minstacklen    proc    near
  2711.         assume    ds:nothing,es:nothing
  2712.         mov    bl,1             ;Don't check for installed code
  2713.         call    asc2bin            ;Get num and convert to binary
  2714.         jc    minstacklen_exit    ;Check for error
  2715.         cmp    al,126
  2716.         jb    minstacklen_1
  2717.         mov    dx,offset errmsg12    ;Stack length too big
  2718.         stc
  2719.         jmp    short minstacklen_exit
  2720. minstacklen_1:
  2721.         or     al,al            ;Make sure min length is not
  2722.         jne    minstacklen_2        ; specified at 0. If so,
  2723.         inc    al            ; change to 1.
  2724. minstacklen_2:
  2725.         mov    es:[minlength],al    ;Save minimum length parameter
  2726. minstacklen_exit:
  2727.         ret
  2728. minstacklen    endp
  2729.  
  2730. ;-----------------------------------------------------------------------------
  2731. ; SETPARAMETER - Common code used by the set stack and set buffer and set
  2732. ;                minimum command length routines.
  2733. ; Entry:  DS:SI - points to ascii number
  2734. ;            BL - Flag to indicate check for installed code, BL=0, check.
  2735. ; Exit:      CF - Clear if sucessful, Set if error.
  2736. ;-----------------------------------------------------------------------------
  2737. setparameter    proc    near
  2738.         assume    ds:nothing,es:nothing
  2739.         mov    dx,offset errmsg4     ;Can't change parameter msg
  2740.         cmp    cs:[alrdy_installed],1    ;If already installed don't
  2741.         je     setparam_error          ;  change parameter.
  2742.         call    asc2bin
  2743. setparam_exit:
  2744.         ret
  2745. setparam_error:
  2746.         stc                ;Set error flag.
  2747.         jmp    short setparam_exit
  2748. setparameter    endp
  2749.  
  2750. ;-----------------------------------------------------------------------------
  2751. ; CHECKCASE - sets the respect case flag for command stack searches.
  2752. ; Entry:     ES - segment of the installed code
  2753. ;         DS:SI - points to check case switch
  2754. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  2755. ;-----------------------------------------------------------------------------
  2756. checkcase    proc    near
  2757.         assume    ds:nothing,es:nothing
  2758.         lodsb                ;Get cmd line switch
  2759.         dec    cx
  2760.         xor    ah,ah            ;Assume no check case
  2761.         cmp    al,'-'
  2762.         je    checkcase_1
  2763.         inc    ah
  2764.         cmp    al,'+'
  2765.         jne    checkcase_error        ;If not + or -, error.
  2766. checkcase_1:
  2767.         mov    es:chk_case,ah
  2768.         clc
  2769. checkcase_exit:
  2770.         ret
  2771. checkcase_error:
  2772.         stc
  2773.         mov    dx,offset errmsg15
  2774.         jmp    short checkcase_exit
  2775. checkcase    endp
  2776. ;-----------------------------------------------------------------------------
  2777. ; CMDSEPCHAR - sets the multiple command seperator character
  2778. ; Entry:     ES - segment of the installed code
  2779. ;         DS:SI - points to sep char
  2780. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  2781. ;-----------------------------------------------------------------------------
  2782. cmdsepchar    proc    near
  2783.         assume    ds:nothing,es:nothing
  2784.         mov    dx,offset errmsg4     ;Can't change parameter msg
  2785.         cmp    cs:[alrdy_installed],1    ;If already installed don't
  2786.         stc                            ;  change parameter.
  2787.         je     cmdsepchar_exit
  2788.         lodsb                ;Get cmd line switch
  2789.         dec    cx
  2790.         mov    es:multi_switch,al
  2791.         clc
  2792. cmdsepchar_exit:
  2793.         ret
  2794. cmdsepchar    endp
  2795.  
  2796. ;-----------------------------------------------------------------------------
  2797. ; SRCH_LIST  determines if a string is in a list.
  2798. ; Entry: DS:SI - Pointer to *end* ASCII string to find.
  2799. ;     CS:DI - Pointer to list of ASCIIZ strings.
  2800. ;           DX - Length of string to search for.
  2801. ; Exit:     CF - Clear if string found
  2802. ;        BX - If CF clear, index into list
  2803. ;-----------------------------------------------------------------------------
  2804. srch_list     proc    near
  2805.         assume    cs:code,ds:nothing,es:nothing
  2806.         push    cx
  2807.         push    si
  2808.         push    es
  2809.  
  2810.         push    cs
  2811.         pop    es
  2812.         xor    bx,bx            ;Zero index counter
  2813.         jcxz    srchl_3
  2814.         sub    si,dx
  2815.         dec    si
  2816. srchl_1:
  2817.         push    si
  2818.         mov    cx,dx            ;Restore command size
  2819.         repe    cmpsb            ;Compare command
  2820.         pop    si
  2821.         jne    srchl_11
  2822.         cmp    byte ptr es:[di],0    ;See if at end of compare str
  2823.         je    srch_list_exit
  2824. srchl_11:        
  2825.         inc    bx            ;Inc count in list
  2826.         xor    al,al
  2827.         cmp    es:[di-1],al        ;See if at end of word
  2828.         jne    srchl_2
  2829.         dec    di
  2830. srchl_2:
  2831.         mov    cx,10            ;Scan to next zero
  2832.         repne    scasb
  2833.         cmp    es:[di],al            ;See if second zero. If so
  2834.         jne    srchl_1         ;  end of list.
  2835. srchl_3:
  2836.         stc                ;Indicate string not found
  2837. srch_list_exit:
  2838.         pop    es
  2839.         pop    si
  2840.         pop    cx
  2841.         ret
  2842. srch_list     endp
  2843.  
  2844. ;-----------------------------------------------------------------------------
  2845. ; LCASE_STR - Converts a string enclosed in {} to lower case.
  2846. ; Entry: DS:SI - Pointer to string 
  2847. ;           CX - Max length of string
  2848. ; Exit:     DX - Length of string
  2849. ;-----------------------------------------------------------------------------
  2850. lcase_str    proc    near
  2851.         xor    dx,dx            ;Zero length count
  2852. lcase_1:
  2853.         lodsb
  2854.         cmp    al,"]"
  2855.         je    lcase_exit
  2856.         cmp    al,"A"
  2857.         jb    lcase_2
  2858.         cmp    al,"Z"
  2859.         ja    lcase_2
  2860.         or    al,20h            ;Convert to lower case
  2861. lcase_2:
  2862.         inc    dx
  2863.         loop    lcase_1
  2864.         stc                ;Error because eol
  2865.         ret
  2866. lcase_exit:
  2867.         dec    cx            ;Carry not changed by dec
  2868.         ret
  2869. lcase_str    endp
  2870.  
  2871. ;-----------------------------------------------------------------------------
  2872. ; LISTKEYS prints the keys assignments.
  2873. ; Entry:  ES - segment of the installed code
  2874. ;-----------------------------------------------------------------------------
  2875. shifts        db    "ssca321"
  2876. shifts_end    =    $
  2877. listkeys    proc    near
  2878.         assume    ds:nothing,es:nothing
  2879.         push    cx
  2880.         push    si
  2881.         push    ds
  2882.         push    es
  2883.         mov    ax,es            ;DS = installed seg
  2884.         mov    ds,ax
  2885.         push    cs            ;ES = CS
  2886.         pop    es
  2887.  
  2888.         assume    es:code
  2889.  
  2890.         mov    dx,offset infomsg6      ;Print header
  2891.         call    printmsgcr
  2892.  
  2893.         mov    si,ds:keylist_base
  2894.         mov    bx,ds:cmdlist_base
  2895.         mov    cx,ds:keys_cnt
  2896. listkey_1:
  2897.         push    cx
  2898.         call    printtab
  2899.         mov    al,"["            ;Print opening bracket
  2900.         call    print_char
  2901.         lodsw
  2902.         push    ax
  2903.         mov    cx,offset shifts_end - offset shifts
  2904.         mov    di,offset shifts
  2905. listkey_1a:
  2906.         shr    ah,1
  2907.         jc    listkey_1b
  2908.         inc    di
  2909.         loop    listkey_1a
  2910.         jmp    short listkey_12
  2911. listkey_1b:
  2912.         mov    al,cs:[di]
  2913.         call    print_char
  2914.         mov    al,'-'
  2915.         call    print_char
  2916. listkey_12:
  2917.         pop    ax
  2918.         and    ah,8fh            ;Strip off custom shifts
  2919.         mov    di,offset keycodes
  2920.         mov    cx,(offset keycodes_end - offset keycodes) shr 1
  2921.         repne    scasw
  2922.         jne    listkey_7
  2923.         dec    di
  2924.         dec    di
  2925.         cmp    di,offset single_key_end
  2926.         jae    listkey_2        ;See if single char or
  2927.         and    di,0fff8h        ;  named key.
  2928.         mov    ax,es:[di]
  2929.         call    print_char
  2930.         jmp    short listkey_5
  2931. listkey_1j:
  2932.         jmp    short listkey_1
  2933. listkey_2:
  2934.         sub    di,offset single_key_end
  2935.         mov    cl,3
  2936.         shr    di,cl
  2937.         mov    cx,di
  2938.         mov    di,offset keynames
  2939.         call    getname
  2940.         call    printmsg
  2941. listkey_5:
  2942.         mov    al,"]"            ;Print closing bracket
  2943.         call    print_char
  2944.         call    printtab
  2945.         call    printtab
  2946.         mov    ax,ds:[bx]        ;Get command function ptr
  2947.  
  2948.         cmp    ax,offset alias_str    ;See if text assignment
  2949.         je    listkey_8
  2950.  
  2951.         mov    di,offset keylist_entry
  2952.         mov    cx,(offset keylist_e_end - offset keylist_entry) shr 1
  2953.         repne    scasw
  2954.         jne    listkey_7
  2955.         sub    di,offset keylist_entry
  2956.         shr    di,1
  2957.         mov    cx,di
  2958.         dec    cx
  2959.         mov    di,offset keycmds    ;Find command name and
  2960.         call    printname        ;  print it.
  2961. listkey_7:
  2962.         mov    dx,offset endmsg
  2963.         call    printmsg
  2964.         inc    bx            ;Advance cmd tbl ptr
  2965.         inc    bx
  2966.         pop    cx
  2967.         loop    listkey_1j
  2968.         clc
  2969.         pop    es
  2970.         pop    ds
  2971.         pop    si
  2972.         pop    cx
  2973.         ret
  2974. listkey_8:
  2975.         mov    ax,ds:[si-2]        ;Get back key
  2976.         push    es
  2977.         push    ds
  2978.         pop    es
  2979.         call    searchkey        ;Find text
  2980.         pop    es
  2981.         push    si
  2982.         lea    si,[di+6]
  2983.         xor    cx,cx
  2984.         mov    cl,[di+3]
  2985. listkey_9:
  2986.         lodsb                ;Print it
  2987.         call    print_char
  2988.         loop    listkey_9
  2989. listkey_10:
  2990.         pop    si
  2991.         jmp    short listkey_7
  2992. listkeys    endp
  2993. ;-----------------------------------------------------------------------------
  2994. ; PRINTNAME prints a string from a list
  2995. ; Entry:  CS:DI - pointer to list
  2996. ;            CX - entry to return in list
  2997. ;-----------------------------------------------------------------------------
  2998. printname    proc    near
  2999.         assume    ds:nothing,es:nothing
  3000.         mov    al,"["
  3001.         call    print_char
  3002.         call    getname
  3003.         call    printmsg        ;Print it
  3004.         mov    al,"]"
  3005.         call    print_char
  3006.         ret
  3007. printname    endp
  3008. ;-----------------------------------------------------------------------------
  3009. ; GETNAME returns a pointer to a string in a list
  3010. ; Entry:  CS:DI - pointer to list
  3011. ;            CX - entry to return in list
  3012. ; Exit:   CS:DX - ptr to string
  3013. ;-----------------------------------------------------------------------------
  3014. getname        proc    near
  3015.         assume    ds:nothing,es:nothing
  3016.         push    es
  3017.         push    cs
  3018.         pop    es
  3019.         jcxz    getname_exit        ;If no length, punt
  3020.         xor    al,al
  3021. getname_1:
  3022.         cmp    cs:[di],al        ;See if at end of list
  3023.         je    getname_exit
  3024.         push    cx
  3025.         mov    cx,128
  3026.         repne    scasb
  3027.         pop    cx
  3028.         loop    getname_1
  3029. getname_exit:
  3030.         mov    dx,di
  3031.         pop    es
  3032.         ret
  3033. getname        endp
  3034. ;-----------------------------------------------------------------------------
  3035. ; SETKEY modifies the alias list to add function key definitions.
  3036. ; Entry:  DS:SI - pointer to string identifing the function key
  3037. ;            ES - pointer to segment of installed code
  3038. ; Exit:      CF - clear if successful
  3039. ;-----------------------------------------------------------------------------
  3040. setkey        proc    near               
  3041.         assume    ds:nothing,es:nothing
  3042.         push    bp
  3043.         mov    bp,sp
  3044.         sub    sp,2
  3045.  
  3046.         cmp    al,"["            ;Determine alias or key
  3047.         je    setkey_1
  3048.          dec    si                      ;Backup before last key
  3049.          inc    cx
  3050.         jmp    setkey_12
  3051. setkey_1:
  3052.         lodsb                ;Get shift character
  3053.         dec    cx
  3054.         jz    setkey_3        ;Make sure other char
  3055.         xor    bx,bx
  3056.         cmp    byte ptr [si],"-"    ;See if shift modifier
  3057.         jne    setkey_4
  3058.         or    al,20h            ;Convert to lc
  3059.         add    bl,2            ;Assume Shift shift
  3060.         cmp    al,"s"
  3061.         je    setkey_2
  3062.         add    bl,2            ;Assume Ctl shift
  3063.         cmp    al,"c"
  3064.         je    setkey_2
  3065.         add    bl,2            ;Assume Alt shift
  3066.         cmp    al,"a"
  3067.         je    setkey_2
  3068.         mov    bx,4000h
  3069.         cmp    al,"1"            ;First optional shift
  3070.         je    setkey_2
  3071.         mov    bh,20h
  3072.         cmp    al,"2"            ;Second optional shift
  3073.         je    setkey_2
  3074.         mov    bh,10h
  3075.         cmp    al,"3"            ;Third optional shift
  3076.         jne    setkey_badkey
  3077. setkey_2:
  3078.         inc    si            ;Skip past '-'
  3079.         lodsb                ;Get next char
  3080.         sub    cx,2
  3081. setkey_3:
  3082.         jbe    setkey_badkey
  3083. setkey_4:
  3084.         mov    [bp-2],bx        ;Save shift param
  3085. ;
  3086. ; Look up keycode in key name table
  3087. ;
  3088.         push    ax
  3089.         dec    si            ;Back up to first char 
  3090.         inc    cx            ;  in keyname
  3091.         call    lcase_str        ;convert string to lc
  3092.         pop    ax
  3093.         jc    setkey_badkey
  3094.         cmp    dx,1            ;See if string length 1
  3095.         jne    setkey_5
  3096.         push    cx
  3097.         mov    di,offset keyletters
  3098.         mov    cx,offset keyletters_end - offset keyletters
  3099.         push    es
  3100.         push    cs
  3101.         pop    es
  3102.         repne    scasb
  3103.         pop    es
  3104.         pushf
  3105.         not    cx
  3106.         add    cx,offset keyletters_end - offset keyletters
  3107.         mov    bx,cx            ;Copy key table index
  3108.         popf
  3109.         pop    cx
  3110.         je    setkey_6
  3111.         xor    ax,ax
  3112.         jmp    short setkey_61
  3113. setkey_5:
  3114.         mov    di,offset keynames    ;Search list for name
  3115.         call    srch_list
  3116.         jc    setkey_badkey
  3117.         add    bx,offset keyletters_end - offset keyletters
  3118. setkey_6:
  3119.         shl    bx,1            ;mul by entry size
  3120.         shl    bx,1
  3121.         shl    bx,1
  3122.         add    bl,[bp-2]        ;Add shift offset
  3123.         adc    bh,0
  3124.         mov    ax,cs:[bx+offset keycodes]
  3125. setkey_61:
  3126.         mov    dx,offset errmsg16    ;Unsupported key msg
  3127.         or    ax,ax
  3128.         jz    setkey_error
  3129.         or    ah,[bp-1]        ;OR shift flags
  3130.         jmp    short setkey_7
  3131. setkey_badkey:
  3132.         mov    dx,offset errmsg11    ;Bad key assignment msg
  3133. setkey_error:
  3134.         stc
  3135.         jmp    setkey_exit1
  3136. setkey_exitj:
  3137.         jmp    setkey_exit
  3138. setkey_7:
  3139.         mov    [bp-2],ax        ;Save key
  3140.         lodsb                ;Get next character
  3141.         dec    cx
  3142.         jz    setkey_8
  3143.         cmp    al," "
  3144.         jbe    setkey_8        ;Check for another char
  3145.  
  3146.         cmp    al,"*"                  ;Check to see if an * is
  3147.         jne    setkey_badkey        ;  appended to indicate
  3148.         mov    cs:[append_cr],1        ;  append cr to command.
  3149. ;
  3150. ; See if key currently in list
  3151. ;
  3152. setkey_8:
  3153.         push    cx            ;Check current keylist for
  3154.         mov    di,es:keylist_base    ;  for key being assigned.
  3155.         mov    cx,es:keys_cnt
  3156.         mov    ax,[bp-2]        ;Get key combination
  3157.         repne    scasw
  3158.         mov    ax,cx
  3159.         pop    cx
  3160.         jne    setkey_9
  3161.         mov    bx,di            
  3162.         sub    bx,es:keylist_base    
  3163.         call    del_entry        ;Key found.  Delete entry
  3164.         mov    di,es:cmdlist_base    ;  in both key list and
  3165.         add    di,bx            ;  cmd list.
  3166.         cmp    word ptr es:[di-2],offset alias_str
  3167.         pushf
  3168.         call    del_entry
  3169.         dec    es:keys_cnt
  3170.         popf                ;See if key cmd an alias
  3171.         jne    setkey_9
  3172.         mov    ax,[bp-2]        ;Get key combination
  3173.         call    searchkey        ;Search alias list
  3174.         jc    setkey_9
  3175.         push    si
  3176.         push    ds
  3177.         push    es
  3178.         pop    ds            ;DS:SI = entry to delete
  3179.         mov    si,di
  3180.         call    delete_aliasent
  3181.         pop    ds
  3182.         pop    si
  3183. setkey_9:
  3184.         jcxz    setkey_exitj
  3185.         xor    bl,bl            ;Point to next word
  3186.         call    scanline             ;See if cmd assignment or
  3187.         jc    setkey_exit        ;  alias.
  3188.         mov    dx,offset alias_str
  3189.         cmp    al,"["
  3190.         jne    setkey_10
  3191.  
  3192.         call    lcase_str        ;convert string to lc
  3193.         jc    setkey_badkey
  3194.         mov    di,offset keycmds    ;Search list for cmd name
  3195.         call    srch_list
  3196.         mov    dx,offset errmsg17    ;Unknown editor cmd
  3197.         jc    setkey_exit1
  3198.         shl    bx,1            ;mul by entry size
  3199.         mov    dx,cs:[bx+offset keylist_entry]
  3200. setkey_10:
  3201.         mov    di,es:keylist_base    ;Save key code in
  3202.         mov    ax,es:keys_cnt        ;  key list
  3203.         cmp    ax,MAXKEYS
  3204.         jb    setkey_11
  3205.         mov    dx,offset errmsg19    ;Too many keys
  3206.         jmp    setkey_error
  3207. setkey_11:
  3208.         shl    ax,1
  3209.         add    di,ax
  3210.         mov    bx,[bp-2]        ;Save key code
  3211.         mov    es:[di],bx
  3212.         inc    es:keys_cnt
  3213.  
  3214.         mov    di,es:cmdlist_base    ;Save key cmd in cmd list.
  3215.         add    di,ax
  3216.         mov    es:[di],dx
  3217.         cmp    dx,offset alias_str
  3218.         jne    setkey_exit
  3219.         sub    si,4            ;Back up to keycode.
  3220.         add    cx,4
  3221.         mov    word ptr ds:[si],5050h    ;Save fake key on cmd line
  3222. setkey_12:
  3223.         call    setalias                ;Use SETALIAS to save text
  3224.         jnc    setkey_13
  3225.         dec    es:keys_cnt        ;If error, remove key
  3226.         jmp    short setkey_exit1
  3227. setkey_13:
  3228.         mov    ax,5050h
  3229.         call    searchkey
  3230.         mov    bx,[bp-2]        ;Save real key code
  3231.         mov    es:[di+4],bx
  3232.         mov    byte ptr es:[di+2],0    ;Indicate key not alias.
  3233. setkey_exit:
  3234.         clc
  3235. setkey_exit1:
  3236.         mov    sp,bp
  3237.         pop    bp
  3238.         ret
  3239. setkey        endp
  3240. ;-----------------------------------------------------------------------------
  3241. ; DEL_ENTRY - Deletes an entry in a word sized list
  3242. ; Entry: ES:DI - Points to entry to delete + 1
  3243. ;           AX - Number of entries remaining in list
  3244. ;-----------------------------------------------------------------------------
  3245. del_entry    proc    near
  3246.         assume    ds:nothing,es:nothing
  3247.         push    cx
  3248.         mov    cx,ax
  3249.         jcxz    del_entry_exit
  3250. del_entry_1:
  3251.         mov    dx,es:[di]
  3252.         mov    es:[di-2],dx
  3253.         inc    di
  3254.         inc    di
  3255.         loop    del_entry_1
  3256. del_entry_exit:
  3257.         pop    cx
  3258.         ret
  3259. del_entry    endp
  3260. ;-----------------------------------------------------------------------------
  3261. ; SETALIAS modifies the alias list according to command line agruments.
  3262. ; Entry:  DS:SI - pointer to string to be inserted into alias list.
  3263. ;            ES - pointer to segment of installed code.
  3264. ; Exit:      CF - clear if successful
  3265. ;-----------------------------------------------------------------------------
  3266. setalias    proc    near
  3267.         assume    ds:nothing,es:nothing
  3268.         push    bp
  3269.         push    es
  3270.         xor    bl,bl            ;Find 1st character on
  3271.         call    scanline        ;  command line.
  3272.         jnc    setalias_1        ;If at end of line, exit
  3273.         jmp    setalias_exit1        ;  routine.
  3274. ;
  3275. ;Get length of alias, then search list for matching alias
  3276. ;
  3277. setalias_1:
  3278.          dec    si            ;Backup to before 1st char.
  3279.         inc    cx
  3280.         call    searchalias        ;Is there already an alias?
  3281.         mov    byte ptr cs:[alias_inlist],0 ;Assume not in list
  3282.         jc     setalias_2        ;No, continue.
  3283.         inc    byte ptr cs:[alias_inlist]
  3284.         call    delete_aliasent        ;Delete entry from list
  3285. setalias_2:
  3286. ;
  3287. ;Append new alias to the end of the list.
  3288. ;
  3289.         mov     bp,di            ;Save ptr to end of list.
  3290.         add    di,4                    ;Move past length fields.
  3291.         push    es            ;Get max size of alias list.
  3292.         mov    es,cs:[other_seg]
  3293.         mov    dx,es:[aliaslist_size]
  3294.         pop    es
  3295. ;
  3296. ;Append alias to list.
  3297. ;
  3298.         xor    ax,ax            ;Clear character counter
  3299. setalias_3:
  3300.         lodsb                ;Get byte
  3301.         dec    cx            ;Decriment buffer counter.
  3302.         jcxz    setalias_4             ;If at end of file, exit.
  3303.         cmp    al,13             ;See if at end of line.
  3304.         jne    setalias_6             ;No, continue.
  3305. setalias_4:
  3306.         cmp    byte ptr cs:[alias_inlist],0
  3307.         jne    setalias_5            ;Was alias in list?
  3308.         jmp    setalias_notnfil    ;No, incomplete alias specifed
  3309. setalias_5:
  3310.         jmp    setalias_exit        ;Yes, alias simply erased.
  3311. setalias_6:
  3312.         cmp    al,' '            ;See if at end of tag.
  3313.         je    setalias_8        ;Yes, exit copy loop
  3314.         cmp    al,9            ;Check for tab
  3315.         je    setalias_8
  3316.         cmp    di,dx             ;See if alias list is full
  3317.         jbe    setalias_7          ;No, continue
  3318.         jmp    setalias_full        ;Yes, exit routine
  3319. setalias_7:
  3320.         stosb                ;No, add character to list
  3321.         inc    ah               ;Inc size of tag
  3322.         jmp    short setalias_3
  3323. setalias_8:
  3324.         mov    es:[bp+2],ah        ;Save size of alias
  3325. ;
  3326. ;Append command to alias list.
  3327. ;
  3328.         mov    cs:[caps_flag],0    ;Initialize setcaps flag.
  3329.         xor    bx,bx            ;Find 1st character in
  3330.         call    scanline        ;  command.
  3331.         jc    setalias_5        ;If no command, exit
  3332.         xor    ah,ah            ;Clear character counter
  3333. setalias_9:
  3334.         cmp    al,"%"            ;Check for environment var
  3335.         jne    setalias_11        ;  by checking for % signs.
  3336.         cmp    cs:[caps_flag],0    ;If caps flag set capitialize
  3337.         jne    setalias_10        ;  string before saving.
  3338.         mov    bl,ds:[si]        ;Get next character
  3339.         cmp    bl,'*'
  3340.         je    setalias_11
  3341.         cmp    bl,"0"            ;If numeric, assume this is
  3342.         jb    setalias_10        ;  a line parameter, not an
  3343.         cmp    bl,"9"            ;  environment variable so
  3344.         jbe    setalias_11        ;  don't set caps flag.
  3345.         cmp    bl,"%"            ;Don't let double % signs
  3346.         je    setalias_11        ;  indicate environment var.
  3347. setalias_10:
  3348.         not    byte ptr cs:[caps_flag]    ;Toggle caps flag
  3349. setalias_11:
  3350.         cmp    cs:[caps_flag],0    ;Capitialize environment
  3351.         je    setalias_12        ;  variables so they will
  3352.         call    capit            ;  match when searched for in
  3353.                         ;  the environment block.
  3354. setalias_12:
  3355.         cmp    al,'$'            ;Check for DOSKEY sequence
  3356.         jne    setalias_129        ;If $0-9 or $*, just sub
  3357.         mov    bl,ds:[si]        ;  % for $.
  3358.         cmp    bl,'*'
  3359.         je    setalias_121
  3360.         cmp    bl,'0'
  3361.         jb    setalias_122
  3362.         cmp    bl,'9'
  3363.         ja    setalias_122
  3364. setalias_121:
  3365.         mov    al,'%'
  3366.         jmp    short setalias_129
  3367. setalias_j9:
  3368.         jmp    short setalias_9
  3369. setalias_122:
  3370.         lodsb                ;Get next char
  3371.         dec    cx
  3372.         call    capit
  3373.         cmp    al,'$'
  3374.         je    setalias_129
  3375.         mov    cs:[caps_flag],0    ;Clear cap flag
  3376.         mov    bl,al            ;Check for b, g, l, t or $.
  3377.         mov    al,'<'
  3378.         cmp    bl,'L'
  3379.         je    setalias_129
  3380.         mov    al,'|'
  3381.         cmp    bl,'B'
  3382.         je    setalias_129
  3383.         mov    al,'>'
  3384.         cmp    bl,'G'
  3385.         je    setalias_129
  3386.         mov    al,es:[multi_switch]
  3387.         cmp    bl,'T'
  3388.         je    setalias_129
  3389.         mov    dx,offset errmsg18    ;Bad $ switch
  3390.         jmp    short setalias_error
  3391. setalias_129:
  3392.         cmp    di,dx             ;See if alias list is full
  3393.         ja     setalias_full        ;Yes, exit routine
  3394.         stosb                ;Append character on list
  3395.         inc    ah               ;Inc character counter.
  3396.         jcxz    setalias_13        ;Check for end of file.
  3397.         lodsb                ;Get next character
  3398.         dec    cx            ;Dec file counter.
  3399.         cmp    al,13            ;See if carriage return.
  3400.         jne    setalias_j9             ;If not continue
  3401. setalias_13:
  3402.         cmp    cs:[append_cr],1    ;If flag set, append carrage
  3403.         jne    setalias_14        ;  return to command.
  3404.         mov    al,13
  3405.         inc    ah
  3406.         stosb
  3407.         mov    cs:[append_cr],0    ;Clear flag
  3408. setalias_14:
  3409.         mov    es:[bp+3],ah        ;Save command size
  3410.         mov    word ptr es:[di],-1    ;Set new end of list flag
  3411.         mov    ax,di                  ;Save end pointer to list
  3412.         add    ax,2            ;Make room for the end flag.
  3413.         mov    cs:[aliaslist_end],ax
  3414.         sub    di,bp            ;Compute size of entry
  3415.         mov    es:[bp],di        ;Put size over old end flag.
  3416.         inc    cs:[file_linecount]    ;Point counter to next line.
  3417. setalias_exit:
  3418.         clc
  3419. setalias_exit1:
  3420.         pop    es            ;Restore ptr to installed seg
  3421.         pop    bp
  3422.         ret
  3423. setalias_full:
  3424.         mov    dx,offset errmsg9    ;Alias list too large msg.
  3425.         jmp    short setalias_error
  3426. setalias_notnfil:
  3427.         mov    dx,offset errmsg13    ;Alias not in list.
  3428. setalias_error:
  3429.         stc
  3430.         jmp    short setalias_exit1
  3431. setalias    endp
  3432.  
  3433. ;-----------------------------------------------------------------------------
  3434. ; CAPIT - Converts char in AL to upper case
  3435. ;-----------------------------------------------------------------------------
  3436. capit        proc    near
  3437.         cmp    al,"a"            ;  match when searched for in
  3438.         jb     capit_exit         ;  the environment block.
  3439.         cmp    al,"z"
  3440.         ja     capit_exit
  3441.         and    al,0dfh            ;Make character uppercase.
  3442. capit_exit:
  3443.         ret
  3444. capit        endp        
  3445. ;-----------------------------------------------------------------------------
  3446. ; LOADALIASFILE loads a file containing a list of alias commands.
  3447. ; Entry:  DS:SI - pointer to the name of the file to open
  3448. ; exit:      CX - size of the file in bytes
  3449. ;            CF - clear if successful
  3450. ;-----------------------------------------------------------------------------
  3451. loadaliasfile    proc    near
  3452.         assume    ds:nothing,es:nothing
  3453.         xor    bl,bl
  3454.         call    scanline        ;Find 1st char of filename.
  3455.         mov     dx,si            ;Copy filename pointer
  3456.         inc    bl            ;Find end of filename
  3457.         call    scanline
  3458.         mov    byte ptr [si-1],0    ;Make filename ASCIIZ.
  3459.         dec    dx
  3460.         mov    ax,3d00h        ;Open file (Read only)
  3461.         int    21h
  3462.         jc    loadfile_error
  3463.         mov    bx,ax            ;Copy file handle
  3464. ;
  3465. ;Save the name of the file for error messages.
  3466. ;
  3467.         push    si
  3468.         push    es
  3469.         mov    di,offset filenam_field
  3470.         push    cs
  3471.         pop    es
  3472.         mov    si,dx
  3473. loadfile_1:
  3474.         lodsb
  3475.         stosb
  3476.         or    al,al
  3477.         jne    loadfile_1
  3478.         mov    byte ptr es:[di-1],"0"    ;Terminate string with 0.
  3479.         pop    es
  3480.         pop    si
  3481. ;
  3482. ;Open file and read contents into file buffer.
  3483. ;
  3484.         mov    ah,3fh            ;Read alias file
  3485.         xor    dx,dx            ;Point to base of file buffer.
  3486.         mov    cx,cs:[filebuf_size]    ;Get size of file buffer.
  3487.         shl    cx,1            ;Convert to bytes
  3488.         shl    cx,1
  3489.         shl    cx,1
  3490.         shl    cx,1
  3491.          int    21h
  3492.         mov    si,ax
  3493.         mov    byte ptr ds:[si],13    ;Append a CR to end of file.
  3494.         mov     cx,ax            ;Save new file size
  3495.         xor    si,si            ;Reset file pointer.
  3496.         mov    ah,3eh            ;Close file.
  3497.         int    21h
  3498.         mov    cs:[file_linecount],1    ;Reset line counter.
  3499. loadfile_exit:
  3500.         clc
  3501. loadfile_exit1:
  3502.         ret
  3503. loadfile_error:
  3504.         stc
  3505.         mov    dx,offset errmsg6    ;Bad filename specified.
  3506.         jmp    short loadfile_exit1
  3507. loadaliasfile    endp
  3508. ;-----------------------------------------------------------------------------
  3509. ; LISTALIAS prints status info followed by the alias list to screen.
  3510. ; Entry:  ES - segment of the installed code
  3511. ;-----------------------------------------------------------------------------
  3512. listalias    proc    near
  3513.         assume    ds:nothing,es:nothing
  3514.         push    ds
  3515. ;
  3516. ;Print Command stack size and amount of alias buffer space remaining
  3517. ;
  3518.         mov    dx,offset infomsg2    ;Print size of command stack
  3519.         call    printmsg
  3520.         mov    ax,es:[cmdstack_size]    ;Get size of command stack
  3521.         cwd
  3522.         mov    bx,32
  3523.         div    bx
  3524.         call    hex2asc            ;Print size
  3525.         mov    dx,offset infomsg3    ;Print min cmd length
  3526.         call    printmsg
  3527.         xor    ax,ax
  3528.         mov    al,es:[minlength]    ;Get min cmd length to stack
  3529.         call    hex2asc            ;Print length
  3530.         mov    dx,offset infomsg4    ;Print label to buffer size
  3531.         call    printmsg
  3532.  
  3533.         lds    si,es:[aliaslist_ptr]    ;Get pointer to alias list
  3534.         xor    dx,dx
  3535. listalias_1:
  3536.         cmp    word ptr [si],-1    ;Scan through alias list to
  3537.         je    listalias_2        ;  find the end of the list.
  3538.                 add    si,[si]            ;Point to next entry
  3539.         mov    dh,1
  3540.         jmp    short listalias_1
  3541. listalias_2:
  3542.         push    dx
  3543.         mov    ax,es:[aliaslist_size]    ;Get offset to end of buffer
  3544.         sub    ax,si            ;Subtract end of alias list
  3545.         sub    ax,2            ;Correct for end pointer
  3546.         call    hex2asc            ;Print size
  3547.         mov    dx,offset infomsg5    ;Indicate if alias translation
  3548.         call    printmsg        ;  is enabled or disabled
  3549.         mov    dx,offset infomsg5d    ;Disabled message
  3550.         cmp    byte ptr es:[chk_alias],0    ;See if alias enabled
  3551.         je    listalias_3
  3552.         mov    dx,offset infomsg5e     ;Enabled message
  3553. listalias_3:
  3554.         call    printmsg
  3555.         pop    dx
  3556.  
  3557.          test    dh,1                  ;See if any aliases found
  3558.          je    listalias_4        ;If no aliases, skip 
  3559.         mov    si,offset infomsg7+2    ;Kluge to erase comment
  3560.         mov    word ptr cs:[si],2020h    ;  chars from header.
  3561.         call    listalias1
  3562. listalias_4:
  3563.         mov    dx,offset infomsg8    ;Print pointer to help msg
  3564.         call    printmsgcr
  3565.         pop    ds
  3566.         ret
  3567. listalias    endp        
  3568. ;-----------------------------------------------------------------------------
  3569. ; LISTALIAS1 prints the alias list to screen.
  3570. ; Entry:  ES - segment of the installed code
  3571. ;-----------------------------------------------------------------------------
  3572. listalias1    proc    near
  3573.         assume    ds:nothing,es:nothing
  3574.         push    ds
  3575.         mov    dx,offset infomsg7    ;Print header
  3576.         call    printmsgcr
  3577.         xor    cx,cx            ;Clear CX
  3578.         lds    si,es:[aliaslist_ptr]    ;Get pointer to alias list
  3579. listalias1_1:
  3580.         mov    bx,si            ;Save pointer to entry.
  3581.          cmp    byte ptr [si+2],0    ;See if key definition
  3582.          jne    listalias1_2        ;If so, skip entry
  3583.         add    si,[bx]
  3584.         jmp    short listalias1_3
  3585. listalias1_2:
  3586.         call    printtab
  3587.                 add    si,4             ;Point SI to alias string
  3588.         mov    cl,[bx+2]        ;Get length of alias
  3589.         call    print_string        ;Print alias to screen
  3590.         call    printtab
  3591.         call    printtab
  3592.         mov    cl,[bx+3]        ;Get length of command
  3593.         call    print_string        ;Print command to screen
  3594.         mov    dx,offset endmsg    ;Append carriage return to
  3595.         call    printmsg        ;  advance to next line.
  3596. listalias1_3:
  3597.         cmp    word ptr [si],-1    ;Check for end of list. SI
  3598.         jne    listalias1_1        ;  points to the next entry.
  3599. listalias1_exit:
  3600.         pop    ds
  3601.         clc
  3602.         ret
  3603. listalias1    endp
  3604. ;-----------------------------------------------------------------------------
  3605. ; PRINTTAB prints a TAB character to the screen.
  3606. ; Entry:  ES - segment of the installed code
  3607. ;-----------------------------------------------------------------------------
  3608. printtab    proc    near
  3609.         assume    ds:nothing,es:nothing
  3610.         mov    al,9            ;Print TAB character
  3611.         call    print_char
  3612.         ret
  3613. printtab    endp
  3614.  
  3615. ;-----------------------------------------------------------------------------
  3616. ; ENABLEALIAS enables alias translation.
  3617. ; Entry:  ES - segment of the installed code
  3618. ;-----------------------------------------------------------------------------
  3619. enablealias    proc    near
  3620.         assume    ds:nothing,es:nothing
  3621.         mov    byte ptr es:[chk_alias],1    ;Enable alias
  3622.         clc
  3623.         ret
  3624. enablealias    endp
  3625.  
  3626. ;-----------------------------------------------------------------------------
  3627. ; DISABLEALIAS disables alias translation.
  3628. ; Entry:  ES - segment of the installed code
  3629. ;-----------------------------------------------------------------------------
  3630. disablealias    proc    near
  3631.         assume    ds:nothing,es:nothing
  3632.         mov    byte ptr es:[chk_alias],0    ;Disable alias
  3633.         clc
  3634.         ret
  3635. disablealias    endp
  3636.  
  3637. ;-----------------------------------------------------------------------------
  3638. ; INSCURSOR Toggles the insert cursor to underline/block
  3639. ; Entry:  ES - segment of the installed code
  3640. ;-----------------------------------------------------------------------------
  3641. inscursor     proc    near
  3642.         assume    ds:nothing,es:nothing
  3643.         xor    byte ptr es:[insert_cursor],1    ;Toggle block flag
  3644.         clc
  3645.         ret
  3646. inscursor     endp
  3647.  
  3648. ;-----------------------------------------------------------------------------
  3649. ; REMOVE uninstalls the installed program from memory.
  3650. ;-----------------------------------------------------------------------------
  3651. remove        proc    near
  3652.         assume    ds:nothing,es:nothing
  3653.         push    ds
  3654.         mov    dx,offset errmsg1    ;Not installed msg
  3655.         cmp    cs:[alrdy_installed],0    ;See if installed
  3656.         je     remove_exit           ;Not installed, error
  3657.  
  3658.         mov    cx,es            ;Get installed segment
  3659.         mov    ax,3521h                ;Get DOS vector
  3660.         int    21h
  3661.         mov    ax,es            ;Check to make sure DOS
  3662.         cmp    ax,cx            ;  vector not modified.
  3663.         jne    remove_error
  3664.  
  3665.         mov    ax,352fh                ;Get MUX vector
  3666.         int    21h
  3667.         mov    ax,es            ;Check to make sure MUX
  3668.         cmp    ax,cx            ;  vector not modified.
  3669.         jne    remove_error
  3670.  
  3671.         lds    dx,es:[int2fh]        ;Get old interrupt 2F vector
  3672.         mov    ax,252fh        ;Set interrupt
  3673.         int    21h
  3674.  
  3675.         lds    dx,es:[int21h]        ;Get old interrupt 21 vector
  3676.         mov    ax,2521h        ;Set interrupt
  3677.         int    21h
  3678.  
  3679.         mov    cx,es:[env_segment]
  3680.         mov    ah,49h            ;Free code block
  3681.         int    21h
  3682.         mov    es,cx            ;Free environment block
  3683.         mov    ah,49h
  3684.         int    21h
  3685.         mov    dx,offset infomsg1    ;Indicate uninstalled.
  3686.         mov    byte ptr filenam_field,0 ;Clear filename field
  3687. remove_exit:
  3688.         stc
  3689.         pop    ds
  3690. remove_exit1:    ret
  3691. remove_error:
  3692.                  mov    dx,offset errmsg3    ;Can't remove error msg
  3693.         jmp    short remove_exit
  3694.  
  3695. remove        endp
  3696.  
  3697. ;-----------------------------------------------------------------------------
  3698. ; COMMENT_LINE allows comments in the alias file by skipping to the next
  3699. ; carriage return.
  3700. ; Entry:  SI - pointer to ASCII string
  3701. ;         CX - file length
  3702. ;-----------------------------------------------------------------------------
  3703. comment_line    proc near
  3704.         assume    ds:nothing,es:nothing
  3705. comment_loop:
  3706.         push    es
  3707.         push    ds
  3708.         pop    es
  3709.         mov    di,si            ;Copy file pointer
  3710.         mov    al,13            ;Scan for carriage return.
  3711.         repne    scasb
  3712.         inc    cs:[file_linecount]    ;Inc file line counter.
  3713.         mov    si,di            ;Restore file pointer.
  3714.         pop    es
  3715.         clc
  3716.          ret
  3717. comment_line    endp
  3718.  
  3719. ;-----------------------------------------------------------------------------
  3720. ; ASC2BIN - converts an ASCII number of the command line to hex.
  3721. ; Entry:  DS:SI - pointer to ASCII number
  3722. ;-----------------------------------------------------------------------------
  3723. asc2bin        proc    near
  3724.         push    bx
  3725.         xor    bl,bl
  3726.         call    scanline        ;Find next character.
  3727.         mov    di,offset errmsg5    ;Bad number message
  3728.         jc    asc_error        ;If no number found, error
  3729.         mov    bl,al            ;Copy first digit.
  3730.                 xor    ax,ax            ;Clear out sum
  3731.         xor    bh,bh            ;Clear high byte for word adds
  3732. asc_loop:
  3733.         cmp    bl," "          ;If space, assume end of
  3734.         jbe    asc_exit        ;  number.
  3735.         cmp    bl,"]"            ;Exit if closing bracket
  3736.         je    asc_exit        ;  encountered
  3737.         sub    bl,"0"            ;Check for valid number then
  3738.         jb    asc_error        ;  convert to binary.
  3739.         cmp    bl,9
  3740.         ja    asc_error
  3741.         mov    dx,10            ;DX holds base multiplier
  3742.         mul    dx             ;Shift over current number
  3743.         jc    asc_overflow        ;If overflow, indicate error
  3744.         add    ax,bx            ;Add new digit to sum.
  3745.         jcxz    asc_exit        ;If end of file, exit.
  3746.         mov    bl,ds:[si]        ;Get next ASCII character
  3747.         inc    si            ;Point to next character
  3748.         dec    cx            ;Dec file size counter
  3749.         jmp    short asc_loop        ;Go back for more
  3750. asc_exit:
  3751.         clc                ;Clear error flag.
  3752. asc_exit1:
  3753.         pop    bx
  3754.         ret
  3755. asc_overflow:
  3756.         mov    di,offset errmsg12    ;Number too large message.
  3757. asc_error:
  3758.         mov    dx,di            ;Copy message pointer.
  3759.         stc                ;Set error flag.
  3760.         jmp    short asc_exit1
  3761. asc2bin        endp
  3762. ;-----------------------------------------------------------------------------
  3763. ; SCANLINE performs the same function as SCAN4CHAR but keeps track of the
  3764. ; carriage returns.
  3765. ; Entry:  SI - pointer to ASCII string
  3766. ;         BL - 0 = find next char, 1 = find next space
  3767. ;         CX - file length
  3768. ; Exit:   AL - first nonspace character
  3769. ;         CF - set if carriage return found
  3770. ;-----------------------------------------------------------------------------
  3771. scanline    proc    near
  3772.         call    scan4char        ;Find the next char.
  3773.         jnc    scanline_exit
  3774.         inc    cs:[file_linecount]    ;Point to next line.
  3775.         stc
  3776. scanline_exit:
  3777.         ret
  3778. scanline    endp
  3779.          even
  3780. end_of_code    =    $
  3781. code        ends
  3782.  
  3783. end        main
  3784. 
  3785.